Liczby zmiennoprzecinkowe a zamiana na system binarny

Odpowiedz Nowy wątek
2019-07-11 09:16
0

Cześć wszystkim,

Jeśli chodzi o typ całkowitoliczbowy (np. int) to można przypisać mu wartość również przez int a = 0b1000011000.
Aby podglądnąć reprezentację binarną wystarczy string binary = Convert.ToString(number, 2) (dlaczego nie działa to dla liczb ujemnych, to znaczy działa poprawnie z tym, że najbardziej znaczące bity mają wartość 1).

A teraz chciałbym zrobić to samo tylko dla typu double, ale z tą różnicą, że wykorzystam do tego notację naukową (tak jak to domyślnie komputer robi).
Tutaj link do artykułu, z którego korzystałem: https://www.samouczekprogramisty.pl/liczby-zmiennoprzecinkowe/
Ale jest problem...
double a = 0b1000101010100101010100011000001 jest traktowane jako liczba całkowita, a nie notacja naukowa
string binary = Convert.ToString(number, 2), gdzie number to typ double nie działa

Takie 3 problemy napotkałem i nie mogę ich przeskoczyć.

wielkie dzięki za pomoc,
miłego dnia

Pozostało 580 znaków

2019-07-11 10:37
2

dlaczego nie działa to dla liczb ujemnych, to znaczy działa poprawnie z tym, że najbardziej znaczące bity mają wartość 1

Strzelam, że chodzi ci o kod U2: https://pl.wikipedia.org/wiki[...]%C5%82nie%C5%84_do_dw%C3%B3ch

double a = 0b1000101010100101010100011000001 jest traktowane jako liczba całkowita, a nie notacja naukowa

Literały z b są traktowane zawsze jako liczby całkowite. Tak definiuje standard C#.

string binary = Convert.ToString(number, 2), gdzie number to typ double nie działa

Najlepiej ci będzie wykorzystać BitConverter:

double d = BitConverter.Int64BitsToDouble(Convert.ToInt64(binary, 2));

Pozostało 580 znaków

2019-07-11 10:37
2

Co do ujemnych integerów binarnie, są one inaczej kodowane, bit z lewej to bit znaku, dlatego 32 - bitowa integer ma zakres od -2^31 do 2^31 - 1, gdyż jeden bit idzie na znak. Kodowane można przedstawić tak:
~|a| + 1;
czyli liczba ujemna to negacja bitowa wartości bezwzględnej z liczby plus jeden. Dla -2(dla uproszczenia 8-bitowo):
~|-2| + 1 =>
~00000010 + 1 =>
11111101 + 00000001 =
11111110.
Stąd jedynki na początku.

EDYCJA: Bity liczby double. Zgodnie ze specyfikacją double to zmienna 64-cztero bitowa, od bitu 63-ciego:
bit znaku;
11 bitów wykładnika;
53 bity mantysy, przy czym bit 53-trzeci jest równy jeden.
Czyli, wartość wynosi:
(-1)^bit znaku * (1, mantysa) * 2 ^(wykładnik - 1023).
Odejmowanie 1023 - takie kodowanie.
Przykład, weźmy hexagonalne: 3F F0 00 00 00 00 00 00 w Big Endian:
Bit znaku = 0, czyli (-1)^0 = 1 - liczba dodatnia;
Wykładnik: 3FF, czyli 011 1111 1111 = 1023(dec) (pierwszy bit poszedł na znak);
Mantysa: 1, 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 czyli 1.0 (decymalnie).
Finalnie: (-1) ^ 0 * (1, 0) * 2^(1023 - 1023) = 1 * (1,0) * 1 = 1.0.
Możesz spróbować napisać konwerter, generalnie:

  1. Zapisujesz bity liczby float do bajtów.
  2. Kastujesz to do uint_64.
  3. Teraz:

edytowany 3x, ostatnio: lion137, 2019-07-11 11:44

Pozostało 580 znaków

2019-07-11 10:54
1
Barteker napisał(a):

double a = 0b1000101010100101010100011000001 jest traktowane jako liczba całkowita, a nie notacja naukowa

To to samo co double a = 1163045057, dlaczego miałoby być „notacją naukową”?

Pozostało 580 znaków

2019-07-11 12:02
1

Nie notacja naukowa tylko IEEE 754 double-precision binary floating-point format: binary64

Chociaz powiedzmy ze jest to faktycznie odmiana notacji naukowej* ;)


01010100 01110101 01110100 01100001 01101010 00100000 01101110 01101001 01100101 00100000 01101101 01100001 00100000 01101110 01101001 01100011 00100000 01100011 01101001 01100101 01101011 01100001 01110111 01100101 01100111 01101111 00101110 00100000 01001001 01100011 00100000 01110011 01110100 01101111 01101110 01110100 00101110
edytowany 1x, ostatnio: stivens, 2019-07-11 12:06

Pozostało 580 znaków

2019-07-11 20:47
0

Dziękuję za odpowiedzi, teraz mi się dużo rozjaśniło.

Pozostało 580 znaków

2019-07-11 21:49
0

Dodajmy, nie wiem czy TY też tego oczekujesz, wielu oczekuje, żeby liczba pamiętała "jak została zainicjowana", sposobem binarnym, dziesiętnym, hexem itd...
Nie ma czegoś takiego, liczba to po prostu liczba.

Pozostało 580 znaków

2019-07-12 14:50
0

Możesz użyć specjalnej klasy do konwertowania
Najpierw zamieniasz liczbę double na 8 bajtów a potem ewentualnie te bajty na bity . W drugą stronę tak samo
albo możesz zrobić sobie sam konwerter do każdego rodzaju typu np.

 using System;
namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            byte[] bity = ZamienNaBity(-0b1111111111111111111111111111111);
            Console.WriteLine(-0b1111111111111111111111111111111);
            for (int i = 0; i < 32; i++)
            {
                Console.Write(bity[i]);
            }
            Console.WriteLine();
            bity = ZamienNaBity(-27.0F);
            for (int i = 0; i < 32; i++)
            {
                Console.Write(bity[i]);
            }
            Console.WriteLine();
        }

        static byte[] ZamienNaBity(int liczbaI)
        {
            byte[] bity = new byte[32];

            for (int i = 31; i >= 0; i--)
            {
                if ((liczbaI & 1) == 1) bity[i] = 1;
                else
                    bity[i] = 0;
                liczbaI = liczbaI >> 1;
            }
            return bity;
        }

        static byte[] ZamienNaBity(float liczbaF)
        {
            byte[] bity = new byte[32];
            unsafe
            {
                int* t1 = (int*)&liczbaF;

                int liczbaI = *t1;

                for (int i = 31; i >= 0; i--)
                {
                    if ((liczbaI & 1) == 1) bity[i] = 1;
                    else
                        bity[i] = 0;
                    liczbaI = liczbaI >> 1;
                }
                return bity;
            }
        }
    }
}
edytowany 3x, ostatnio: Zimny Krawiec, 2019-07-12 15:56
I co to drukuje dla, np., 0.5 double? - lion137 2019-07-12 15:32
liczby float wychodzą inaczej niż double - Zimny Krawiec 2019-07-12 15:48
Możesz porównać wyniki z klasą BitConverter czy dają takie same wyniki - Zimny Krawiec 2019-07-12 15:51
Floaty maja mniej bitow. Teraz jestem na telefonie, zobacze pozniej. - lion137 2019-07-12 16:03

Pozostało 580 znaków

2019-07-12 15:43
0
using System;
namespace ConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            byte[] bity;
            bity = ZamienNaBity(0.5);
            for (int i = 0; i < 64; i++)
            {
                Console.Write(bity[i]);
            }
            Console.WriteLine();

        }

        static byte[] ZamienNaBity(double liczbaD)
        {
            byte[] bity = new byte[64];
            unsafe
            {
                long* t1 = (long*)&liczbaD;

                long liczbaL = *t1;

                for (int i = 63; i >= 0; i--)
                {
                    if ((liczbaL & 1) == 1) bity[i] = 1;
                    else
                        bity[i] = 0;
                    liczbaL = liczbaL >> 1;
                }
                return bity;
            }
        }
    }
}

0.5 = 0011111111100000000000000000000000000000000000000000000000000000
0.5F = 00111111000000000000000000000000
Zgadza się ?

edytowany 3x, ostatnio: Zimny Krawiec, 2019-07-12 16:03
Wychodzi mi, że tak, sprawdzałem na razie dla double. - lion137 2019-07-12 23:09

Pozostało 580 znaków

Odpowiedz
Liczba odpowiedzi na stronę

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0