最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Buffer reading and writing floats - Stack Overflow

programmeradmin2浏览0评论

When I write a float to a buffer, it does not read back the same value:

> 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)
> 

Why?

EDIT:

My working theory is that because javascript stores all numbers as double precision, it's possible that the buffer implementation does not properly zero the other 4 bytes of the double when it reads the float back in:

> var b = new Buffer(4)
undefined
> b.fill(0)
undefined
> b.writeFloatBE(0.1,0)
undefined
> b.readFloatBE(0)
0.10000000149011612
>

I think it's telling that we have zeros for 7 digits past the decimal (well, 8 actually) and then there's garbage. I think there's a bug in the node buffer code that reads these floats. That's what I think. This is node version 0.10.26.

When I write a float to a buffer, it does not read back the same value:

> 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)
> 

Why?

EDIT:

My working theory is that because javascript stores all numbers as double precision, it's possible that the buffer implementation does not properly zero the other 4 bytes of the double when it reads the float back in:

> var b = new Buffer(4)
undefined
> b.fill(0)
undefined
> b.writeFloatBE(0.1,0)
undefined
> b.readFloatBE(0)
0.10000000149011612
>

I think it's telling that we have zeros for 7 digits past the decimal (well, 8 actually) and then there's garbage. I think there's a bug in the node buffer code that reads these floats. That's what I think. This is node version 0.10.26.

Share Improve this question edited Nov 24, 2014 at 5:03 Kevin asked Nov 24, 2014 at 4:23 KevinKevin 25.3k20 gold badges107 silver badges158 bronze badges 10
  • It's a float, not a double. If you need the precision of a double, write a double instead. – Qantas 94 Heavy Commented Nov 24, 2014 at 4:27
  • Probably should be using the byte size specific read / write methods. – Ryan Commented Nov 24, 2014 at 4:27
  • @self: I'm not sure I understand. Are you saying that writeFloatBE should not be used to write a floating point number to a buffer? – Kevin Commented Nov 24, 2014 at 4:29
  • @Kevin: writeDoubleBE is your friend. – Qantas 94 Heavy Commented Nov 24, 2014 at 4:29
  • @Qantas: if I'm implementing a platform neutral wire format, and the other side is expecting a 4 byte float, I can't exactly do that, can I? – Kevin Commented Nov 24, 2014 at 4:31
 |  Show 5 more ments

2 Answers 2

Reset to default 5

Floating point numbers ("floats") are never a fully-accurate representation of a number; this is a mon feature that is seen across multiple languages, not just JavaScript / NodeJS. For example, I encountered something similar in C# when using float instead of double.

Double-precision floating point numbers are more accurate and should better meet your expectations. Try changing the above code to write to the buffer as a double instead of a float:

var b = new Buffer(8);
b.fill(0);
b.writeDoubleBE(3.14159, 0);
b.readDoubleBE(0);

This will return:

3.14159

EDIT:

Wikipedia has some pretty good articles on floats and doubles, if you're interested in learning more:

  • http://en.wikipedia/wiki/Floating_point
  • http://en.wikipedia/wiki/Double-precision_floating-point_format

SECOND EDIT:

Here is some code that illustrates the limitation of the single-precision vs. double-precision float formats, using typed arrays. Hopefully this can act as proof of this limitation, as I'm having a hard time explaining in words:

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]);

This will print:

float 3.141590118408203
double 3.14159

Also, if my understanding is correct, single-precision floating point numbers can store up to 7 total digits (significant digits), not 7 digits after the decimal point. This means that they should be accurate up to 7 total significant digits, which lines up with your results (3.14159 has 6 significant digits, 3.141590118408203 => first 7 digits => 3.141590 => 3.141590 === 3.14159).

readFloat in node is implemented in c++ and bytes are interpreted exactly the way your piler stores/reads them. I doubt there is a bug here. What I think is that "7 digits" is incorrect assumption for float. This answer suggest 6 digits (and it's the value of std::numeric_limits<float>::digits10 ) so the result of readFloatBE is within expected error

发布评论

评论列表(0)

  1. 暂无评论