0

I'm getting unexpected float values when I read in my file. So I have a program that accumulates scores for elements in my object e.g. [{a:0.001}, {b:0.002},....]. The scores are incremented by 0.001. When I exit out, the array is written to a file with the following function:

function(filename, result, msg)
{
  var fs = require('fs');
  var stream = fs.createWriteStream(filename);
  stream.once('open', function(fd) 
  {
      stream.write(JSON.stringify(result));
      stream.end(function()
      {
        console.log(msg);
      });
  });
}

and when I start the program, in another module, the object is read in as so:

fs.readFile('scoreboard.json', 'utf8', function (err, data) 
{
 console.log(JSON.parse(data));
}

When I initially run my script, it produces the expected results - scores that are multiples of 0.001. But when I save and reload the object, the scores turn up as:

[{a:0.009000000000000001},{b:0.011000000000000003}]

Is this occurring because of the way fs is reading and writing floats? To fix this should I explicitly convert the scores to floats after loading and convert them back into strings before writing?

Soubriquet
  • 3,100
  • 10
  • 37
  • 52
  • 3
    See [IEEE-754](http://en.wikipedia.org/wiki/IEEE_754-1985). – maerics Jan 07 '15 at 17:53
  • Not quite a duplicate I guess, but I'd look at [this answer](http://stackoverflow.com/questions/1458633/elegant-workaround-for-javascript-floating-point-number-problem). – loganfsmyth Jan 07 '15 at 20:26

1 Answers1

1

This is a fact of floating-point numbers. I'd take a look at this answer. The core of it is that not all numbers can be 100% accurately represented by floating-point, and the next-closest possible representation is chosen.

Your issue is not related to fs.readFile, you can see it easily enough with this:

v = 0;
for (var i = 0; i < 30; i++){
    v += 0.001;
    console.log(v);
}

prints

0.001
0.002
0.003
0.004
0.005
0.006
0.007
0.008
0.009000000000000001
0.010000000000000002
0.011000000000000003
0.012000000000000004
0.013000000000000005
0.014000000000000005
0.015000000000000006
0.016000000000000007
0.017000000000000008
0.01800000000000001
0.01900000000000001
0.02000000000000001
0.02100000000000001
0.022000000000000013
0.023000000000000013
0.024000000000000014
0.025000000000000015
0.026000000000000016
0.027000000000000017
0.028000000000000018
0.02900000000000002
0.03000000000000002

If you need 100% accuracy, you'll need to choose a storage format that does not have to round. For your example, why increment by 0.001 instead of storing an integer count and multiplying by 0.001 on load?

Community
  • 1
  • 1
loganfsmyth
  • 156,129
  • 30
  • 331
  • 251