openexchangerates / accounting.js

A lightweight JavaScript library for number, money and currency formatting - fully localisable, zero dependencies.
http://openexchangerates.github.io/accounting.js
MIT License
4.95k stars 528 forks source link

formatNumber fails after many runs in chrome #63

Open jnordberg opened 11 years ago

jnordberg commented 11 years ago

I ran in to a really strange bug

var largeNumber = 2749606250;
var expected = '2,749,606,250';
var result;

for (var i = 0; i < 1000; i++) {
    result = accounting.formatNumber(largeNumber);
    if (result != expected) {
        console.log('failed at', i, result);
        break;
    }
}

console.log('done', result);

// failed at 393 1,545,361,046
// done 1,545,361,046 

After ~400 runs the result becomes wildly inaccurate. I can only reproduce in chrome so it might be some optimizer bug. (tested nodejs 0.8 and firefox 13, both chrome stable and beta fails)

Here's a jsfiddle that can reproduce it in chrome: http://jsfiddle.net/nSavd/3/

MrChriZ commented 11 years ago

Seems to be down to the this part of the code Math.abs(number || 0)

Not sure what the OR is doing here. Bizare it only happens in Chrome though and sometimes it does work...

MrChriZ commented 11 years ago

http://jsfiddle.net/CcQL2/1/

Stripped down jsFiddle

jnordberg commented 11 years ago

Good find, i'll create a issue on the chromium bug tracker if you haven't already.

Seems to be only Math.abs that causes this, function f(n) { return n; } f(largenum || 0); works as expected

jnordberg commented 11 years ago

https://code.google.com/p/chromium/issues/detail?id=230333

jheath commented 11 years ago

This only happens on numbers larger than (2^31)-1. For some reason after a number of iterations, Math.abs turns the number from a float into into a 32-bit Int.

Any bits beyond 32 are discarded. If bit 31 is 1, the number becomes its negative complement. Afterwards the expected absolute value takes place and the value is returned.

flexd commented 11 years ago

Any progress on this? I think this is what I am experiencing. I have some numbers >7 billion, and when the value passed 7,088,534,343.62 (+- something) it becomes 1,501,400,249.62

It's actually correctly formatted the first number several times, and then suddenly it fails for one and all the ones that follow.

driverdan commented 11 years ago

This also affects floats with a large number of decimal places, such as 139.6920137421. They get truncated to an int (139.6920137421 becomes 139).

latentflip commented 10 years ago

The above pull request fixes this issue. The chrome bug which causes is fixed in canary (30+) but the current version of chrome still exhibits this behaviour.