La entrada es un búfer que contiene números flotantes de precisión simple (32 bits, little endian).
Lo que quiero producir es una cadena JSON que contenga esos números, conservando exactamente los mismos valores sin cambios de precisión.
El problema es: tan pronto como el valor se almacena en un number JS, se convierte a 64 bits, introduciendo cambios de precisión.
Por ejemplo:
const buffer = Buffer.from("cdcccc3d", "hex"); // cdcccc3d is 0.1 in 32 bits float LE console.log(buffer.readFloatLE(0)); // 0.10000000149011612 => bad ¿Cómo obtener este valor como una cadena que conserva la precisión original sin conversión? Aquí: "0.1" .
Punto de bonificación si logro producir una cadena JSON que contiene el número con la precisión original: { "value": 0.1 } .
Los bytes little-endian cd cc cc 3d son, en orden big-endian, 3d cc cc cd, o los bits 0011 1101 1100 1100 1100 1100 1100 1101.
En la codificación IEEE-754 binary32, 0 es el bit de signo, 011 1101 1 son los bits de campo de exponente y 100 1100 1100 1100 1100 1101 son los bits de campo de significado.
Un bit de signo 0 significa positivo.
Los bits de campo de exponente 011 1101 1 son 123 como binario sin formato. Los exponentes se codifican con un sesgo de 127, por lo que el exponente representado es 123−127 = −4.
Dado que el campo exponente no es cero (o todos unos, que se usa para infinitos y NaN), se antepone un 1 a los bits del campo significado, formando 1100 1100 1100 1100 1100 1101. Como binario sin procesar, esto es 13,421,773. Los significados se codifican con una escala de 2 23 , por lo que el significado representado es 13 421 773/2 23 .
Combinando el signo, el exponente y el significado, el valor representado es +2 −4 •13,421,773/2 23 = 0.100000001490116119384765625. Este es el valor exacto representado, sin error. Entonces puede ver que el número producido para él, "0.10000000149011612" es exacto, hasta donde llega.