14

I am trying to deal with JavaScript values such as 23.45, but I want to be able to do mathematical operations on these values (addition, subtraction, multiplication, division) without running into floating point issues. Yes, I might need to round the results sometimes, but I would like it to give reasonable answers.

Consider this in JavaScript:

24.56 * .3

Yields

7.36799999999

I would like it to come out with 7.368.

Most languages have either a decimal or currency data type to deal with this. Has anyone built a class that can handle this sort of data effectively, or is there any other solution for dealing with these sorts of numbers without having to constantly adjust for floating point errors?

informatik01
  • 16,038
  • 10
  • 74
  • 104
Jeff Davis
  • 4,736
  • 4
  • 38
  • 44

7 Answers7

10

Integers.

There is no need to use floating-point for currency. Use fixed-point, where the number of decimal points is 0.

You count in pennies (or possibly in tenths of pennies).

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • This is helpful. However, I was hoping someone had already done the grunt work of creating some kind of class/framework for dealing with such a pseudo-decimal representation using integers. – Jeff Davis May 11 '11 at 16:31
  • 4
    @Jeff: They did. They lived thousands of years ago and they discovered how to multiply by 100. – Lightness Races in Orbit May 11 '11 at 16:32
  • The question is about javascript. JS don't have integers, everything is doubles. http://stackoverflow.com/a/3605946/446536 – geon Sep 21 '12 at 14:06
  • @geon: Regardless, if you pack only whole-number values into a double then you do not get these accuracy problems. That is to say, the object with value `5.0` and type `double` is [mathematically] an integer. – Lightness Races in Orbit Sep 29 '12 at 20:59
  • I guess you missed the javascript tag. There are no integers variables in javascript (and for any pedants that may be reading this: typed arrays don't count). All numbers are double-precision floating point in javascript. Up to about $45,035,996,273,704.96 *can* be exactly represented in pennies (there are sufficient mantissa bits to represent it with some room to spare). – doug65536 Sep 14 '13 at 21:30
  • @doug65536: I guess you missed the word "mathematically"; `3.0` is an integer stored in an object of a floating-point type. (Not to be confused with an integer stored in an object of an integral type which, correct, do not exist in Javascript.) Double or no double, you will not have inaccuracy problems with whole-number values, because these can always be stored with a finite number of bits. (Though you may not get 100% precision, if you exceed the number of bits available in your type.) – Lightness Races in Orbit Sep 15 '13 at 13:20
  • @LightnessRacesinOrbit Yes, I did say use pennies (whole numbers), 4503599627370496 can be represented exactly, and adding 1 to it works correctly, which is where I got that number in my comment. We agree, I just added that you can safely store up to about 45 trillion "dollars" using pennies, in a double. – doug65536 Sep 15 '13 at 13:39
  • 3
    So that's great for USD currency, but what about non 100th based currencies, such as BitCoins which have up to 8 decimal places. What about fractional cents (US Gubment tax)? – Alan Mar 14 '14 at 22:36
  • 1
    @Alan: Oh please like anyone cares about BitCoins. If you need sub-penny precision, divide by another ten. It's not rocket science. – Lightness Races in Orbit Mar 15 '14 at 01:41
  • 1
    so much despise in this thread, what's wrong with you people ? how do you deal with division and percentages with integer-cents ? – Pierre-Alexis Ciavaldini Jan 28 '19 at 16:20
5

Instead of using integers (which have their own problems)

I would use the bignumber.js library

leszek.hanusz
  • 5,152
  • 2
  • 38
  • 56
  • 1
    Nice. This is what I was looking for. Looks like it didn't exist when I originally asked the question, but there it is now. – Jeff Davis Mar 02 '15 at 19:24
2

There is Math

The Math object is build into the JavaScript spec so every browser has it natively.

As for data types, JavaScript has Number. That's it. We have no other number data type. The best think to do is to try and work with Integers.

Raynos
  • 166,823
  • 56
  • 351
  • 396
  • `number` is a floating point type and is a poor choice for currencies due to inherent lack of precision and accuracy in certain value ranges – RaidenF May 17 '18 at 13:33
1

ku4jQuery-kernel contains both a money class and a math utility that contain operations and rounding, including round, roundUp and roundDown. These are nice methods because you can pass a value to round to. For example you can do $.math.round(3.4567, -2) and it will round the number 3.4567 to the nearest 10^-2. The same goes for money. $.money(100.87).divide(2).roundUp().toString() will yield "$50.44". You can go further and add the denomination of money as a second parameter, say "B" for Bitcoin, $.money(100.87, "B").divide(2).roundUp().toString(). You can find more about this library here ku4jQuery-kernel and more libraries that you may find useful here kodmunki github. These libraries are closely maintained and used in many production projects. If you decide to try them, I hope that you find them useful! Happy coding :{)}

kodmunki
  • 11
  • 1
1

New kid on the block: moneysafe. It's open-source, and uses a functional approach that allows smart composition.

$(.1) + $(.2) === $(.3).cents;

https://github.com/ericelliott/moneysafe

François Zaninotto
  • 7,068
  • 2
  • 35
  • 56
1

currency.js or decimal.js should do what you need.

As the names imply, they are designed to handle similar things but decimal.js has many more methods to handle much more than currency, hence the size difference:

  • currency.js - 2.8k (1.3k gzipped)
  • decimal.js - 31.9k (12.7k gzipped)
jake_d
  • 11
  • 2
0

The toFixed method can round to a given number of decimals.

There is also a Javascript sprintf implementation.

Jose Solorzano
  • 393
  • 4
  • 6