缓冲区读写浮点数

Kev*_*vin 4 javascript node.js

当我将浮点数写入缓冲区时,它不会读回相同的值:

> var b = new Buffer(4);
undefined
> b.fill(0)
undefined
> b.writeFloatBE(3.14159,0)
undefined
> b.readFloatBE(0)
3.141590118408203
> 
(^C again to quit)
> 
Run Code Online (Sandbox Code Playgroud)

为什么?

编辑:

我的工作理论是,因为 javascript 将所有数字存储为双精度,所以当缓冲区实现读回浮点数时,可能无法正确地将双精度数的其他 4 个字节归零:

> var b = new Buffer(4)
undefined
> b.fill(0)
undefined
> b.writeFloatBE(0.1,0)
undefined
> b.readFloatBE(0)
0.10000000149011612
>
Run Code Online (Sandbox Code Playgroud)

我认为这表明小数点后 7 位数字为零(实际上是 8 位),然后就是垃圾。我认为读取这些浮点数的节点缓冲区代码中存在错误。那就是我所想的。这是节点版本 0.10.26。

Rob*_*ell 5

浮点数(“floats”)从来都不是数字的完全准确的表示;这是多种语言的共同特征,而不仅仅是 JavaScript / NodeJS。例如,我在 C# 中使用float而不是 时遇到了类似的情况double

双精度浮点数更准确,应该更好地满足您的期望。尝试更改上面的代码以将双精度型而不是浮点型写入缓冲区:

var b = new Buffer(8);
b.fill(0);
b.writeDoubleBE(3.14159, 0);
b.readDoubleBE(0);
Run Code Online (Sandbox Code Playgroud)

这将返回:

3.14159
Run Code Online (Sandbox Code Playgroud)

编辑:

维基百科有一些关于浮点数和双精度数的非常好的文章,如果您有兴趣了解更多信息:

第二次编辑:

下面是一些代码,说明使用类型化数组的单精度浮点格式与双精度浮点格式的限制。希望这可以作为这种限制的证明,因为我很难用语言解释:

var floats32 = new Float32Array(1),
    floats64 = new Float64Array(1),
    n = 3.14159;

floats32[0] = n;
floats64[0] = n;

console.log("float", floats32[0]);
console.log("double", floats64[0]);
Run Code Online (Sandbox Code Playgroud)

这将打印:

float 3.141590118408203
double 3.14159
Run Code Online (Sandbox Code Playgroud)

另外,如果我的理解正确的话,单精度浮点数最多可以存储7位数字(有效数字),而不是小数点后7位。这意味着它们应该精确到总共 7 位有效数字,这与您的结果一致(3.14159有 6 位有效数字,3.141590118408203=> 前 7 位数字 => 3.141590=> 3.141590 === 3.14159)。