WeCodeAcademy

Step 2: Represent money exactly

Never use double for money. Binary floating point cannot store most decimals exactly, so errors creep in. Run this and watch 0.1 + 0.2 fail to equal 0.3:

ExampleJava
public class Main {
  public static void main(String[] args) {
    // Floating point cannot store most decimals exactly
    double a = 0.1 + 0.2;
    System.out.println(a);
    System.out.println(a == 0.3);

    double total = 0;
    for (int i = 0; i < 10; i++) total += 0.1;
    System.out.println(total);
    System.out.println(total == 1.0);

    // Whole cents in a long are exact
    long cents = 0;
    for (int i = 0; i < 10; i++) cents += 10;     // ten times 10 cents
    System.out.println(cents + " cents");
    System.out.println(cents == 100);
  }
}
Output
0.30000000000000004
false
0.9999999999999999
false
100 cents
true

The fix is to store whole cents in a long: integers are exact. Wrap them in a small immutable type so the rest of the program cannot mix up cents and dollars, and so printing is in one place. A Java record gives you equality by value, a constructor and accessors for free.

ExampleJava
public class Main {
  record Money(long cents) {
    static Money of(long dollars, int cents) { return new Money(dollars * 100 + cents); }
    static final Money ZERO = new Money(0);

    Money plus(Money other) { return new Money(cents + other.cents); }
    Money minus(Money other) { return new Money(cents - other.cents); }
    boolean isNegative() { return cents < 0; }
    boolean lessThan(Money other) { return cents < other.cents; }

    @Override
    public String toString() {
      String sign = cents < 0 ? "-" : "";
      long abs = Math.abs(cents);
      return String.format("%s$%d.%02d", sign, abs / 100, abs % 100);
    }
  }

  public static void main(String[] args) {
    Money price = Money.of(19, 99);
    Money tip = Money.of(0, 5);
    System.out.println(price);
    System.out.println(price.plus(tip));
    System.out.println(Money.ZERO.minus(tip));
    System.out.println(price.equals(Money.of(19, 99)));     // records compare by value
    Money sum = Money.ZERO;
    for (int i = 0; i < 10; i++) sum = sum.plus(Money.of(0, 10));
    System.out.println(sum);
  }
}
Output
$19.99
$20.04
-$0.05
true
$1.00

Because Money is immutable, plus and minus return new values, so nobody can change a price by accident.

Quick check

Why store money as whole cents in a long?

Finish the quick check (and any code exercise) to complete this lesson, or mark it done yourself.

Tip: use the left and right arrow keys to move between lessons.