# Which data type would you choose for storing Monetary Values, Currency in Java

Carvia Tech | August 10, 2019 | 5 min read | 1 views

Float & Double are bad for financial (even for military use) world, never use them for monetary calculations. If precision is one of your requirements, use `BigDecimal` instead.

Lets see the problem with the help of this example:

All floating point values that can represent a currency amount (in dollars and cents) can not be stored exactly as it is in the memory. So if we want to store 0.1 dollar (10 cents), float/double can not store it as it is, instead binary can store only a closer approximation value (0.100000001490116119384765625 in decimal). The magnitude of this problem becomes significant (known as loss of significance) when we repetitively do arithmetic operations (multiply or divide) using these two data types. Let’s try to understand this fact by taking this simple example

Loss of precision using double
``````public class DoubleForCurrency {

public static void main(String[] args) {
double total = 0.2;
for (int i = 0; i < 100; i++) {
total += 0.2;
}
System.out.println("total = " + total);
}
}``````
Program output:
`total = 20.19999999999996`

The output should have been `20.20` (20 dollars and 20 cents), but floating point calculation made it `20.19999999999996`. That’s loss of precision (or loss of significance)

## Real cause of loss of significance

Floating-point arithmetic

In computing, floating-point arithmetic (FP) is arithmetic using formulaic representation of real numbers as an approximation so as to support a trade-off between range and precision.

From Wikipedia

Whether or not a rational number has a terminating expansion depends on the base. For example, in base-10 the number 1/2 has a terminating expansion (0.5) while the number 1/3 does not (0.333…​). In base-2 only rationals with denominators that are powers of 2 (such as 1/2 or 3/16) are terminating. Any rational with a denominator that has a prime factor other than 2 will have an infinite binary expansion. This means that numbers which appear to be short and exact when written in decimal format may need to be approximated when converted to binary floating-point. For example, the decimal number 0.1 is not representable in binary floating-point of any finite precision; the exact binary representation would have a "1100" sequence continuing endlessly:

e = −4; s = 1100110011001100110011001100110011…​, where, as previously, s is the significand and e is the exponent.

When rounded to 24 bits this becomes

e = −4; s = 110011001100110011001101, which is actually 0.100000001490116119384765625 in decimal.

## BigDecimal for the rescue

BigDecimal represents a signed decimal number of arbitrary precision with an associated scale. BigDecimal provides full control over the precision and rounding of the number value. Virtually its possible to calculate value of pi to 2 billion decimal places using BigDecimal, available physical memory being the only limit.

That’s the reason we should always prefer BigDecimal or BigInteger for financial calculations.

Special Notes

Primitive type - int and long are also useful for monetary calculations if decimal precision is not required.

We should really avoid using BigDecimal(double value) constructor instead prefer BigDecimal(String) because BigDecimal (0.1) results in (0.1000000000000000055511151231257827021181583404541015625) being stored in BigDecimal instance. In contrast BigDecimal ("0.1") stores exactly 0.1

Question: What is Precision and Scale?

Precision is the total number of digits (or significant digits) of a real number

Scale specifies number of digits after decimal place For example, 12.345 has precision of 5 (total digits) and scale of 3 (number of digits right of the decimal)

### How to format BigDecimal Value without getting exponentiation in the result & Strip the trailing zeros?

We might get exponentiation in the calculation result if we do not follow some best practices while using `BigDecimal`. Below is the code snippet which shows a good usage example of handling the calculation result using `BigDecimal`.

BigDecimal Rounding
``````import java.math.BigDecimal;

public class BigDecimalForCurrency {

public static void main(String[] args) {
int scale = 4;
double value = 0.11111;
BigDecimal tempBig = new BigDecimal(Double.toString(value));
tempBig = tempBig.setScale(scale, BigDecimal.ROUND_HALF_EVEN);
String strValue = tempBig.stripTrailingZeros().toPlainString();
System.out.println("tempBig = " + strValue);
}
}``````
Program Output
`tempBig = 0.1111`
How would you print a given currency value for Indian Locale (INR Currency)?

`NumberFormat` class is designed specifically for this purpose. Currency symbol & Rounding Mode is automatically set based on the locale using `NumberFormat`. Lets see this in action

NumberFormat example
``````class Scratch {
public static String formatRupees(double value) {
NumberFormat format = NumberFormat.getCurrencyInstance(new Locale("en", "in"));
format.setMinimumFractionDigits(2);
format.setMaximumFractionDigits(5);
format.setRoundingMode(RoundingMode.HALF_EVEN);
return format.format(value);
}

public static void main(String[] args) {
BigDecimal tempBig = new BigDecimal(22.121455);
System.out.println("tempBig = " + formatRupees(tempBig.doubleValue()));
}
}``````
Program Output
`tempBig = Rs.22.12146`

That’s all, everything is taken care by NumberFormat.

### Some precautions

• BigDecimal(String) constructor should always be preferred over BigDecimal(Double), because using `BigDecimal(double)` is unpredictable due to inability of the double to represent 0.1 as exact 0.1

• If double must be used for initializing a BigDecimal, use `BigDecimal.valueOf(double)` which converts Double value to string using Double.toString(double) method

• Rounding mode should be provided while setting the scale

• StripTrailingZeros chops off all the trailing zeros

• toString() may use scientific notation but, toPlainString() will never return exponentiation in its result

### Do you know?

Use of float and double instead of BigDecimal could be fatal in military world

On February 25, 1991, a loss of significance in a MIM-104 Patriot missile battery prevented it from intercepting an incoming Scud missile in Dhahran, Saudi Arabia, contributing to the death of 28 soldiers from the U.S. Army’s 14th Quartermaster Detachment - http://www.gao.gov/products/IMTEC-92-26

Banker’s Rounding Mode

Since the introduction of IEEE 754, the default method (round to nearest, ties to even, sometimes called Banker’s Rounding or `RoundingMode.HALF_EVEN`) is more commonly used USA. This method rounds the ideal (infinitely precise) result of an arithmetic operation to the nearest representable value, and gives that representation as the result. In the case of a tie, the value that would make the significand end in an even digit is chosen.

Buy my ebook for complete question bank

Most of these questions has been answered in my eBook "Cracking the Core Java Interview" updated on June 2018, that you can buy from this link:

###### Find more on this topic: ##### Java Interviews

Interview - Product Companies, eCommerce Companies, Investment Banking, Healthcare Industry, Service Companies and Startups.

Last updated 1 week ago

###### Recommended books for interview preparation:
Book you may be interested in..
Book you may be interested in..
Book you may be interested in..