I'm writing a bank program with a variable long balance
to store cents in an account. When users inputs an amount I have a method to do the conversion from USD to cents:
public static long convertFromUsd (double amountUsd) {
if(amountUsd <= maxValue || amountUsd >= minValue) {
return (long) (amountUsd * 100.0)
} else {
//no conversion (throws an exception, but I'm not including that part of the code)
}
}
In my actual code I also check that amountUsd
does not have more than 2 decimals, to avoid inputs that cannot be accurately be converted (e.g 20.001 dollars is not exactly 2000 cents). For this example code, assume that all inputs has 0, 1 or 2 decimals.
At first I looked at Long.MAX_VALUE
(9223372036854775807 cents) and assumed that double maxValue = 92233720368547758.07
would be correct, but it gave me rounding errors for big amounts:
convertFromUsd(92233720368547758.07)
gives output 9223372036854775807
convertFromUsd(92233720368547758.00)
gives the same output 9223372036854775807
What should I set double maxValue
and double minValue
to always get accurate return values?
BigDecimal
as a temp holderIf you have a very large double (something between Double.MAX_VALUE / 100.0 + 1
and Double.MAX_VALUE
) the calculation of usd * 100.0
would result in an overflow of your double.
But since you know that every possible result of <any double> * 100
will fit in a long you could use a BigDecimal
as a temporary holder for your calculation.
Also, the BigDecimal
class defines two methods which come in handy for this purpose:
By using a BigDecimal
you don't have to bother about specifying a max-value at all -> any given double representing USD can be converted to a long value representing cents (assuming you don't have to handle cent-fractions).
double usd = 123.45;
long cents = BigDecimal.valueOf(usd).movePointRight(2).setScale(0).longValueExact();
Attention: Keep in mind that a double is not able to store the exact USD information in the first place. It is not possible to restore the information that has been lost by converting the double to a BigDecimal
.
The only advantage a temporary BigDecimal
gives you is that the calculation of usd * 100
won't overflow.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With