0

For example:

sum = 0.00;

sum += 46.85 * 0.1;
console.log(sum) // 4.6850000000000005

sum += 179.29 * 0.1;
console.log(sum) // 22.613999999999997

I believe I've had this happen with simple additions and simple multiplications as well.

I understand this is a consequence of the inability to hold floats properly in a computer, which is fine. However, Postgres, as far as I can tell, seems to handle these operations fine with the same numbers. Seems strange that Javascript doesn't seem to, unless I'm missing something.

Anyway, my current fix is to run it like this:

const fixFloatError = (n) => {
  decimalDigitLength = n.match(/\.(\d+)/)[1].length;
  return parseFloat(parseFloat(n).toFixed(decimalDigitLength - 1));
}

let n = String(46.85 * 0.1);
n = fixFloatError(n);

If you're wondering why I'm converting it to a string beforehand, it's because Javascript will automatically turn a float like 22.6139999999999997 into 22.614 as it enters the function (Which is correctly fixed! Regardless of whether you hardcoded that number into the variable or generated it by multiplication), and things like 4.6850000000000005 into 4.6850000000000005 (which hasn't changed). So to get a consistent function that works for both cases I'm passing in the float as a string to maintain its form.

Surely I'm missing something here and there's a simpler solution?

General Grievance
  • 4,555
  • 31
  • 31
  • 45
hosstay
  • 1
  • 1
  • It's very simple - if you need precision, then do not use float point numbers. If not, just take what you get. – PM 77-1 Apr 15 '21 at 21:02
  • @YonatanVainer - Thanks for the link. The accepted answer in that thread does do a good job of explaining things. I am indeed working with currency which is why I need things to be exact. As I figured I'd either need to run a function after each operation or use a custom data type. Thank you for the resource. – hosstay Apr 15 '21 at 21:13
  • "*Postgres, as far as I can tell, seems to handle these operations fine with the same numbers.*" - it's probably not using doubles then – Bergi Apr 15 '21 at 21:55

1 Answers1

0

Just multiply the float by some factor of 10 to create a larger integer portion. Then round the remainder and divide back down by that same factor.

let sum = 46.85 * 0.1;
console.log(sum) // 4.6850000000000005

sum = (Math.round(sum * 1000000000)) /  1000000000;

console.log(sum); // 4.685
Scott Marcus
  • 64,069
  • 6
  • 49
  • 71
  • This does seem to fix the string requirement for my function. Yours does essentially the same thing without requiring I pass it in as a string. I do still have to call it after each operation that I care about using the result, though. That's to be expected without doing a custom datatype as others have suggested. Thanks. – hosstay Apr 15 '21 at 21:10