DEV Community

Pike Msonda
Pike Msonda

Posted on • Edited on

JS float rounding bug

I have been familiarizing myself with Stripe API. So far so good but today I run into this interesting bug. Stripe gives currency amounts using cents (if you are in the US). Obviously when displaying to the end user you need to convert to proper readable USDs.

And when you want to updated or make purchases you have to reconvert to cents for the API to accept the request.

3380 * 0.01 // converts to $33.8  nothing special here.
Enter fullscreen mode Exit fullscreen mode

When completing a payment or charge in my setup. I convert $33.8 dollars back to cents. However when I do so, the resulting amount was not exactly 3338.

33.8 * 100 = 3379.9999999999995
Enter fullscreen mode Exit fullscreen mode

Because of this Stripe retuned an error.

My first solution was to use parseInt but that returned 3379. This is unsatisfactory since 1 cent has been lost.

A more satisfactory solution was to do the following:

33.8.toString().split('.').reduce((a, b) => a * 100 + b * 10) // 3380
Enter fullscreen mode Exit fullscreen mode

Another solution would be to round off the float using toFixed like below:

parseInt(33.8 * 100).toFixed()) // 3380
Enter fullscreen mode Exit fullscreen mode

Top comments (2)

Collapse
 
pengeszikra profile image
Peter Vivo

You right js floating error is quite disturbing.
Here is a little bit more mathematical solution:

const epsilonN = N => num => Math.round( num * N + Number.EPSILON ) / N;
const epsilon2 = epsilonN(1e2);

0.1 + 0.2  // 0.30000000000000004
epsilon2(0.1 + 0.2) // 0.3
epsilon2(33.8 * 100) // 3380
Enter fullscreen mode Exit fullscreen mode
Collapse
 
bloodrave_n profile image
Pike Msonda

This looks much better and safe.