-1

EDIT: This is not a discussion about how great or broken the floating-point implementation in JS is. This is a very specific case, so please do not mark this as a duplicate of a discussion about floating-point.

This is the script I use to calculate the decimal portion of an amount expressed in cents (Ex. 3.34 is 334 cents):

const amount = 334;
const decimal = Math.trunc(100 * ((amount / 100) % 1).toFixed(2));

console.log(decimal); //34

So far so good. If you change the amount to 329 you get 28, which is wrong:

const amount = 329;
const decimal = Math.trunc(100 * ((amount / 100) % 1).toFixed(2));

console.log(decimal); //28

This is due to the fact that (329/100) % 1 = 0.29000000000000004 instead of 0.30, because JS floating-point sucks?

But what is really crazy to me is that while developing a loop to see the cases in which that script breaks using a FOR, it does not break on 329!:

for(let x = 325; x < 335; x++) {
  
  const r = Math.trunc((100 * (( x / 100) % 1)).toFixed(2));
  console.log(x, r);

}

What am I missing here? Why is working when inside the loop and not working when calling the function directly? And how can you calculate this in a robust and reliable way?

DomingoSL
  • 14,920
  • 24
  • 99
  • 173

1 Answers1

0

Analysing this:

const amount = 329;
const decimal = Math.trunc(100 * ((amount / 100) % 1).toFixed(2));
  • (((329/100) % 1).toFixed(2)) returns the STRING "0.29"
  • If converting it back t a number, it is scanned to the nearest possible float 0.289999999999999980. You can proof it by: (+(((329/100) % 1).toFixed(2))).toPrecision(18)
  • Then you multiply the result by 100 and truncate it, so you get the correct value 28.

Functions like toFixed() or toPrecision() are designed to format number for the final output, but not for mathematical calculations.

Solution for you problem:

const amount = 329;
const decimal = amount % 100;

... or if amount can be a float with fractions.

const decimal = math.round(amount) % 100;

One last note: This is a discussion about the implementation of floating-point and how to work with it; and not only for JS!

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Wiimm
  • 2,971
  • 1
  • 15
  • 25