0

IEEE-754 Float Visualizer

Tekintse meg pontosan, hogyan tárolódnak a decimális számok IEEE-754 floatként – előjelbitek, kitevőbitek és mantissza bitek –, és miért nem tárolják pontosan a 0,1-hez hasonló számokat.

Buy Me a Coffee at ko-fi.com
Feldolgozás... 0%
Normalizálás
Számítási kitevő torzítás
Bővülő mantissza bitek
Kész

Eredmény

A számítógép által tárolt minden lebegőpontos szám – JavaScript szám, C float, Python lebegőpont – ugyanúgy van kódolva az IEEE 754 alatt: egy előjelbit, egy kitevőbitek blokkja és egy mantissza (tört) bitek blokkja. Az egyszeres pontosságú (32 bites) 1 előjelbitet, 8 kitevőbitet és 23 mantissza bitet használ; A dupla pontosságú (64 bites) formátum, amely szinte minden nyelv alapértelmezett számtípusa mögött áll, 1 előjelbitet, 11 kitevőbitet és 52 mantissza bitet használ. Ez az eszköz bármilyen beírt decimális számot felvesz, bármelyik szélességben kódolja a böngésző saját DataView/ArrayBuffer float kódolójával – ugyanazon a gépen, amelyen a kód valójában fut –, és minden bitet kiszínez, hogy melyik régióhoz tartozik.

Maga a kódolás három lépést követ, és ez az eszköz mindegyiken végigmegy, ahelyett, hogy csak az utolsó biteket mutatná meg. Először is, normalizálás: a számot 1.mantissza × 2^ kitevővel írjuk át, pontosan egy nullától eltérő számjeggyel a bináris pont előtt (az ehhez túl kicsi számok helyett a szubnormális kezelést kapják, implicit kezdő 1 nélkül). Másodszor, a kitevő torzítása: mivel a kitevőmezőnek mind a pozitív, mind a negatív kitevőt előjel nélküli számként kell tárolnia, egy rögzített torzítás (127 egyszeres pontosság esetén, 1023 dupla pontosság esetén) a mező binárisan történő kiírása előtt kerül hozzáadásra. Harmadszor, a tört mantisszát apránként bővítjük a klasszikus „szorozd meg kettővel, vegyük az egész részt a következő bitnek, a maradékot megtartjuk” metódussal – addig ismételjük, amíg a mantissza mező meg nem telik, ekkor a maradék bitek döntik el, hogy az eredmény felfelé vagy lefelé kerekedik-e (a fele párosra kerekítve, az IEEE-754 alapértelmezett).

Pontosan ez az oka annak, hogy egy olyan közönséges szám, mint a 0,1, nem tárolódik pontosan. Binárisban a 0,1 egy ismétlődő tört (0,0001100110011…, örökre), így egyetlen véges mantissza sem tudja pontosan megtartani – valahol le kell kerekíteni. Kódolja a 0.1-et 32 ​​bites floatként, és olvassa vissza a biteket, és a 0.1-et nem kapja vissza: pontosan 0,100000001490116119384765625-öt kap. A dupla precizitásnak még 29 mantissza bittel kell dolgoznia, így a kerekítési hibája jóval kisebb, de nem is nulla – 0,1, mint egy 64 bites dupla, pontosan 0,100000000000000005551115123125782702118154154156. Ez az eszköz a pontos tárolt értéket nagy egész számok aritmetikával (lebegőpontos billentyűparancsok nélkül) számítja ki, így a begépelt és a hardver által ténylegesen megtartott rés soha nem rejtőzik vagy közelít.

A speciális értékek pontos, fenntartott bitmintákat kapnak normál kódolás helyett: a nulla és a negatív nulla csak nulla kitevővel és mantissza bitekkel rendelkezik (csak az előjelbitek különböznek), a ±Infinity csak egy kitevő bitjei teljesen nulla mantisszával, a NaN pedig csak egy kitevő bitekkel rendelkezik legalább egy mantissza bitkészlettel. Itt minden helyileg fut a böngészőben – semmi, amit beír, nem töltődik fel sehova –, ami biztonságos helyet biztosít a valódi intuíció felépítéséhez a lebegőpontos hibákhoz: miért `0.1 + 0.2 !== 0.3` szinte minden programozási nyelven, miért veszítenek a float32 textúrák a grafikus kódban olyan pontosságból, amit a float64 nem, és miért kellene általában a lebegőpontos bináris kódnak.