Vizualizator števil IEEE-754
Oglejte si natančno, kako je decimalno število shranjeno kot število IEEE-754 s plavajočo vejico – bit predznaka, biti eksponenta in biti mantise – in zakaj števila, kot je 0,1, niso shranjena natančno.
🔒 V celoti obdelano v vašem brskalniku – nič, kar tukaj vnesete, ni nikoli naloženo.
Rezultat
Vsako število s plavajočo vejico, ki ga shrani računalnik – število v JavaScriptu, float v C-ju, float v Pythonu – je kodirano na enak način po standardu IEEE 754: en bit predznaka, blok bitov eksponenta in blok bitov mantise (ulomka). Enojna natančnost (32-bitna) uporablja 1 bit predznaka, 8 bitov eksponenta in 23 bitov mantise; dvojna natančnost (64-bitna), ki je osnova privzetega številskega tipa v skoraj vsakem programskem jeziku, uporablja 1 bit predznaka, 11 bitov eksponenta in 52 bitov mantise. To orodje pretvori poljubno decimalno število v obe širini z uporabo vgrajenega kodirnika float iz brskalnika (DataView/ArrayBuffer) – istega mehanizma, na katerem dejansko teče vaša koda – in vsak bit obarva glede na območje, ki mu pripada.
Samo kodiranje poteka v treh korakih in to orodje vas vodi skozi vse, namesto da bi prikazalo le končne bite. Najprej normalizacija: število se zapiše kot 1,mantisa × 2^eksponent, s točno eno neničelno števko pred binarno vejico (premajhna števila dobijo namesto tega obravnavo podnormalnih števil, brez implicitne vodilne enice). Nato pristranskost eksponenta: ker mora polje eksponenta hraniti pozitivne in negativne eksponente kot nepredznačeno število, se pred zapisom polja v dvojiški obliki doda fiksna pristranskost (127 za enojno, 1023 za dvojno natančnost). Nazadnje se ulomek mantise razširi bit za bitom s klasično metodo »pomnoži z dve, vzemi celi del kot naslednji bit, obdrži ostanek« – ponavlja se, dokler ni polje mantise polno; na tej točki preostali biti odločajo, ali se rezultat zaokroži navzgor ali navzdol (zaokroževanje polovice k sodi vrednosti, privzeto po IEEE-754).
Prav to je razlog, da že tako običajno število 0,1 ni shranjeno natančno. V dvojiški obliki je 0,1 periodični ulomek (0,0001100110011…, v neskončnost), zato ga nobena končna mantisa ne more zajeti natančno – nekje ga je treba zaokrožiti. Kodirajte 0,1 kot 32-bitni float in nazaj preberite bite, pa ne dobite 0,1, ampak natančno 0,100000001490116119384765625. Dvojna natančnost ima na voljo 29 bitov mantise več, zato je njena napaka zaokrožanja precej manjša, a še vedno ni nič – 0,1 kot 64-bitni double je natančno 0,1000000000000000055511151231257827021181583404541015625. To orodje izračuna natančno shranjeno vrednost z veliko-celoštevilsko aritmetiko (brez bližnjic s plavajočo vejico), tako da razlika med tem, kar ste vtipkali, in tem, kar strojna oprema dejansko hrani, ni nikoli skrita ali približna.
Posebne vrednosti dobijo natančne, rezervirane bitne vzorce namesto običajnega kodiranja: ničla in negativna ničla imata vse bite eksponenta in mantise enake 0 (razlikuje se le bit predznaka), ±neskončnost ima vse bite eksponenta enake 1 in mantiso iz samih ničel, NaN pa ima vse bite eksponenta enake 1 in vsaj en bit mantise nastavljen. Vse se izvaja lokalno v vašem brskalniku – nič od tega, kar vnesete, se ne naloži nikamor – zato je to varno okolje za razvoj pravega občutka za napake s plavajočo vejico: zakaj v skoraj vseh programskih jezikih `0.1 + 0.2 !== 0.3`, zakaj teksture float32 v grafični kodi izgubljajo natančnost, ki je float64 ne bi, in zakaj naj se finančna koda dvojiški plavajoči vejici raje v celoti izogne.