I've always been told never to represent money with double or float types, and this time I pose the question to you: why?
I'm sure there is a very good reason, I simply do not know what it is.
I've always been told never to represent money with double or float types, and this time I pose the question to you: why?
I'm sure there is a very good reason, I simply do not know what it is.
To add on previous answers, there is also the option of implementing Joda-Money in Java, besides BigDecimal, when dealing with the problem addressed in the question. Java module name is org.joda.money.
It requires Java SE 8 or later and has no dependencies.
To be more precise, there is a compile-time dependency but it is not required.
<dependency>
<groupId>org.joda</groupId>
<artifactId>joda-money</artifactId>
<version>1.0.1</version>
</dependency>
Examples of using Joda Money:
// create a monetary value
Money money = Money.parse("USD 23.87");
// add another amount with safe double conversion
CurrencyUnit usd = CurrencyUnit.of("USD");
money = money.plus(Money.of(usd, 12.43d));
// subtracts an amount in dollars
money = money.minusMajor(2);
// multiplies by 3.5 with rounding
money = money.multipliedBy(3.5d, RoundingMode.DOWN);
// compare two amounts
boolean bigAmount = money.isGreaterThan(dailyWage);
// convert to GBP using a supplied rate
BigDecimal conversionRate = ...; // obtained from code outside Joda-Money
Money moneyGBP = money.convertedTo(CurrencyUnit.GBP, conversionRate, RoundingMode.HALF_UP);
// use a BigMoney for more complex calculations where scale matters
BigMoney moneyCalc = money.toBigMoney();
Documentation: http://joda-money.sourceforge.net/apidocs/org/joda/money/Money.html
Implementation examples: https://www.programcreek.com/java-api-examples/?api=org.joda.money.Money
Float is binary form of Decimal with different design; they are two different things. There are little errors between two types when converted to each other. Also, float is designed to represent infinite large number of values for scientific. That means it is designed to lost precision to extreme small and extreme large number with that fixed number of bytes. Decimal can't represent infinite number of values, it bounds to just that number of decimal digits. So Float and Decimal are for different purpose.
There are some ways to manage the error for currency value:
Use long integer and count in cents instead.
Use double precision, keep your significant digits to 15 only so decimal can be exactly simulated. Round before presenting values; Round often when doing calculations.
Use a decimal library like Java BigDecimal so you don't need to use double to simulate decimal.
p.s. it is interesting to know that most brands of handheld scientific calculators works on decimal instead of float. So no one complaint float conversion errors.
American currency can easily be represented with dollar and cent amounts. Integers are 100% precise, while floating point binary numbers do not exactly match floating point decimals.