1

I was working on a code requiring some rounding and number formatting, and while writing my unit tests I hit this strange case. Sometimes Number.toFixed() does not round as expected. Further investigation revealed that the rounding logic changes at number 64. Here is an example I run on MDN Number.toFixed() doc site.

function financial(x) {
  return Number.parseFloat(x).toFixed(2);
}

console.log(financial(123.456));
// expected output: "123.46"

console.log(financial(0.004));
// expected output: "0.00"

console.log(financial(0.005));
// expected output: "0.01"

console.log(financial(10.005));
// expected output: "10.01"

console.log(financial(63.005));
// expected output: "63.01" <<== This is still OK.

console.log(financial(64.005));
// expected output: "64.01" <<== THIS RETURNS 64.00, NOT 64.01. WHY?

console.log(financial(100.005));
// expected output: "100.01"  <<== THIS RETURNS 100.00, NOT 100.01. WHY?

console.log(financial(64.006));
// expected output: "64.01"  <<== This is OK as well

console.log(financial(64.015));
// expected output: "64.02"  <<== This is OK as well

console.log(financial(64.105));
// expected output: "64.11"  <<== This is OK as well

console.log(financial('1.23e+5'));
// expected output: "123000.00"

From the code output, and from a few other tests that are not included, it seems like that starting with number 64 and any larger number, if there are two leading zeroes in the decimals followed by digit 5, round up does not happen for toFixed(2). I didn't try with toFixed(3) and 3 leading zeroes. However, if there is any non zero digits in the decimals, rounding happens correctly. The number 64.006 however rounds correctly to 64.01

Is this rounding behavior expected for some reason I don't understand? Is there any work around for this?

Thanks.

Patkos Csaba
  • 682
  • 2
  • 9
  • 16
  • If you want to use numbers for *money*, use a different library. It's an universal advise for almost all programming languages - don't use the native floating point primitives, use something like BigDecimal (in Java) or equivalent, even a library if no built-ins provided. – VLAZ Oct 29 '19 at 05:34
  • A lot of the questions that were marked as duplicates also don't have great answers, but VLAZ is on point.. rounding is unreliable with floats, by design. The issue will creep up in other types of calculations too and it's best to just avoid floats if you want to be exact. I wrote a lib to deal with this for js: https://github.com/evert/bigint-money/ requires a pretty new browser though. – Evert Oct 29 '19 at 06:14
  • The reason is the same as why `0.1 + 0.2 !== 0.3` – FZs Oct 29 '19 at 06:15

0 Answers0