Money is not a float

One suggestion I took to heart is that in order to be great, you need to work on fundamentals. It’s no good to be up to date with the latest and greatest, be they Agile techniques or new technologies, if you’re weak on fundamentals.

So I’m starting a collection of fundamentals, that is certainly not going to be comprehensive. Rather, it’s a random collection of things that I think are fundamental, yet many experienced developers get wrong.

Let us start with a surprising discovery: did you know that the number 1/10 cannot be represented in a finite way in base 2? Yep, it turns out that in base 2 the number 1/10 is periodical, much like the number 1/3 has no finite decimal representation in base 10. But what is the implication for us?

The implication comes when we make the mistake of representing a money in a floating-point number. Suppose you encode the amount of “ten cents” in the floating-point number 0.10. And now look at this program, and guess what happens when it runs.

  public class MoneyIsNotAFloat {
    public static void main(String[] args) {
      double tenCents = 0.1;
      double sum = 0.0;
      for (int i=0; i<10; i++) { 
        sum += tenCents;
        System.out.println("0.1 * " + (i+1) + " = " + sum);
      }
    }
  }  

(Hint: 1.0 times 10 equals… 0.99999999999999).

And this is not a Java problem. The same happens with any language, for it’s a matter of floating point arithmetic.

The simple fact is that floating-point arithmetic is not exact, therefore it should not be used for representing money!

What to use then? One simple solution is to use a plain int to represent an amount of cents. Integer arithmetic is exact. A 32-bit int should be enough for most applications. If you’re worried about overflow, use a BigDecimal type. Java has one, and most modern languages do too. (Just a note: if you use a Java BigDecimal, remember that you should not compare them with “equals”, you must use “compare”. Go figure.)

4 Responses to “Money is not a float”

  1. Massimo Says:

    A few simpler examples…

    #include

    int main()
    {
    printf( “%g\n”, 0.3 – 0.2 – 0.1 );
    printf( “%g\n”, 0.3 – ( 0.2 + 0.1 ) );
    printf( “%g\n”, 0.4 – 0.3 – 0.1 );
    printf( “%g\n”, 0.4 – ( 0.3 + 0.1 ) );

    return 0;
    }

  2. Carlo Says:

    It’s interesting to note this behaviour with (j)ruby:

    ten_cent = 0.10
    sum = 0.0
    10.times {sum += ten_cent}
    puts “sum is #{sum}”

    That results in “1.0” with “native” ruby, and 0.9999 with JRuby.

  3. matteo Says:

    An update: I found this very good article in Stephan Schmidt’s blog: http://codemonkeyism.com/once-and-for-all-do-not-use-double-for-money/

  4. Max Says:

    Some notes on other popular JVM languaes:

    1) Groovy does the “right thing” by default

    this.a = 0.3
    ===> 0.3
    this.a * 3
    ===> 0.9
    this.a.class.name
    ===> java.math.BigDecimal

    2) Scala behave exactly like Java:

    scala> val cent = 0.3
    cent: Double = 0.3
    scala> cent * 3
    res0: Double = 0.8999999999999999

    However, using BigDecimal is straightforward thanks to the implicit conversion:

    scala> val cent : BigDecimal = 0.3
    cent: BigDecimal = 0.3
    scala> cent * 3
    res1: scala.math.BigDecimal = 0.9

Leave a Reply