Which rounding mode to be used for currency manipulation in java? - java

I have read on java site to use BigDecimal for currencies.
http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html
But what rounding mode we should use with? which is the most appropriate one and most widely us

There is no "correct" mode, it depends on the business case. Examples:
When calculating annual taxes, the fractions are often cut off (RoundingMode.FLOOR).
When calculating a bonus, you might want to always round in favor of the customer (RoundingMode.CEILING).
For taxes on a bill, you usually round HALF_UP
When doing complex financial simulations, you don't want to round at all.
The documentation of RoundingMode contains a lot of examples how the different modes work.
To get a better answer, you must tell us what you want to achieve.
That said, BigDecimal is the correct type to use in Java because it can preserve any amount of precision plus it lets you chose the rounding mode most suitable for your case.

Most of the time BigDecimal is the only valid choice for currencies. But the choice of rounding strategy is not that obvious.
The default is HALF_EVEN which happens to be a good choice. This algorithm is known as bankers' rounding (see discussion here).
Another common strategy is HALF_UP which is more intuitive but has slightly worse statistical characteristics.
Also note that in many times (especially in banking and insurances) the rounding strategy will be dictated by business requirements, often different for various use-cases.

Typically you'd use "half up" rounding, like so:
myBigDecimal.setScale(2, RoundingMode.HALF_UP);
This way, you'll round to two decimal places (which most currencies use, e.g. dollars and cents, obviously there are exceptions), and you'll round values such that half a cent or more will round up while less than half a cent will round down. See the javadoc for more details.

For the financial applications ROUND_HALF_EVEN is the most common rounding mode. That mode avoids bias.
But for display you should use NumberFormat class. This class will take care of localization issues for amounts in different currencies. But NumberFormat accepts primitives only. So use last one if you can accept small accuracy change in transformations to a double.

You should never use a decimal type for currencies. Use an integer type. This maintains accuracy buy avoiding rounding error associated with floats
When display an amount then divide by the appropriate factor to get the non-integral portion.

Related

Big datatype in java

I have been working on an application. It is related to shopping business.
There is a model that has:
private Float count;
private Long price;
I want to know the best java datatype for count * price because of huge amount of price and count.
Another hand the overflow is not occured whenprice * count operation.
JSR 354: Money and Currency API
As a solution you can consider an approach with the JavaMoney.org library on GitHub. This library implements the JSR 354: Money and Currency API specification.
The goals of that API:
To provide an API for handling and calculating monetary amounts
To define classes representing currencies and monetary amounts, as well as monetary rounding
To deal with currency exchange rates
To deal with formatting and parsing of currencies and monetary amounts
If you don't want use any library of course you should use BigDecimal.
The maximum value of:
Float is Float.MAX_VALUE, (2-2^23)*2^127, something like 3.40282346638528860e+38 or 340,282,346,638,528,860,000,000,000,000,000,000,000.000000.
Long is Long.MAX_VALUE, 2^63-1, or 9,223,372,036,854,776,000.
Just what kind of shopping business are you running that does not fit in those types?
Floating-point
Actually, you do not want Float for the simple reason that it is based on floating-point technology, and you never use floating-point for money. Never use floating-point for any context where accuracy is important. Floating-point trades away accuracy for speed of execution. Usually, your customers will care about money. So you would never use the float, Float, double, or Double types in Java for such purposes. This workaround is prone to confusion and mistakes obviously, so it requires careful documentation and coding.
BigDecimal
Where accuracy matters, such as money, use BigDecimal. Not because it can handle large numbers, but because it is accurate. Slow, but accurate.
The advice to use BigDecimal applies only where you have a fractional amount such as tracking the pennies on a dollar. If you are using only integer numbers, you have no need for BigDecimal.
Integer workaround for fractional amounts
Indeed a workaround for the floating-point problem in languages lacking an alternative like BigDecimal is to multiple all fractional amounts until they become integers. For example, if doing bookkeeping to the penny on a dollar (United States), then multiple all amounts by 100 to keep a count of whole pennies as an integer rather than a count of fractional dollars.
Integers
As for working with integer numbers in Java, you have multiple simple choices.
For numbers 127 and less, use byte or Byte, using 8 bits.
For numbers 32,767 and less, use short or Short, using 16 bits.
For numbers 2^31-1 and less (about 2 billion), use int or Integer, using 32 bits.
For numbers 2^63-1 and less (about umpteen gazillion), use long or Long, using 64 bits.
For even larger numbers, use BigInteger.
Generally best to use the smallest integer type that can comfortably fit your current values as well as fit foreseeable future values.
The 32-bit or 64-bit types are your main choices for modern hardware. You needn't worry about the smallest types unless working with massive amounts of these values, or are quite constrained on memory. And using BigInteger is overkill for most any business-oriented app. (Science and engineering apps might be a different story.)
See also the Answer by i.merkurev on the JSR 354: Money and Currency API library.
For huge values there are BigDecimal or BigInteger classes. I will use BigDecimal in your case. You never get overflow with this classes.

Representing money with integers/BigInteger vs BigDecimal

Some years ago, I helped write an application that dealt with money and insurance. Initially, we represented money with floating point numbers (a big no-no, I know). Most of the application was just adding and subtracting values, so there weren't any issues. However, specific portions dealt with percentages of money values, hence multiplication and division.
We immediately began suffering from floating point errors and had to do a major refactor. We used an arbitrary precision library which solved that issue. However, it didn't change the fact that you can end up with fractions of a cent. How are you supposed to round that? The short answer is "it's complicated."
Now I'm getting ready to begin work on a similar application to supplant the old one. I've been mulling this over for years. I always thought it would be easiest to create a money datatype that wraps an integer (or BigInteger) to represent the number of pennies with a function to print it to a traditional, human-friendly $0.00 format.
However, researching this, I found JSR 354, the Java Money API that was recently implemented. I was surprised to discover that it backs its representation of money with BigDecimal. Because of that, it includes specific logic for rounding.
What's the advantage to carrying fractions of a cent around in your calculations? Why would I want to do that instead of saying one cent is the "atomic" form of money?
This is a broad question because its answer differs for its implementation.
If I were to purchase 1000 items in bulk for $5, then each item would individually cost $0.005, which is less than what you claim to be the "atomic form" of money, $0.01.
If we considered $0.01 to be the lowest possible amount, then we wouldn't be able to handle calculations in specific situations, like the one in my example.
For that reason, the JavaMoney API handles many fractional digits, ensuring that no precision is lost in cases like these.

Can we replace using Double with BigDecimal completely, any performance overhead?

I have a Java project that deals with a lot money values and the project mainly involves:
reading the data from database,
calculations (process data)
showing to users (no inserts or updates in database are required).
I need precision for only some of the money values and not for all. So here I can do:
using doubles when precision not required or
using BigDecimals for ALL.
I want to know if there will be any performance issues if I use BigDecimal for all the variables? Can I save execution time if I opt for choice 1?
Which way is best? (I am using java 6)
Don't use double for money Why not use Double or Float to represent currency?
Using Big Decimal is 100x slower than the built in primitives and you can't use + and -, / and * with BigDecimal but must use the equivalent BigDecimal method calls.
An alternative is to use int instead of double where you are counting cents or whatever fractional currency equivalent and then when formatting the output to the user, do the appropriate conversions back to show the values the way the user expects.
If you have really large values, you can use long instead of int
It's a trade-off.
With BigDecimal you are working with immutable objects. This means that each operation will cause the creation of new objects and this, for sure, will have some impact on the memory. How much - it depends on a lot of things - execution environment, number and complexity of the calculations, etc. But you are getting precision, which is the most important thing when working with money.
With double you can use primitive values, but the precision is poor and they are not suitable for money calculation at all.
If I had to suggest a way - I would say for sure use BigDecimal when dealing with money.
Have you considered moving some of the calculation logic to the DB layer? This can save you a lot in terms of memory and performance, and you will still keep the precision requirement in tact.
BigDecimal and double are very different types, with very different purposes. Java benefits from having both, and Java programmers should be using both of them appropriately.
The floating point primitives are based on binary to be both space and time efficient. They can be, and typically are, implemented in very fast hardware. double should be used in contexts in which there is nothing special about terminating decimal fractions, and all that is needed is an extremely close approximation to a value that may be fractional, irrational, very big, or very small. There are good implementations of many trig and similar functions for double. See java.lang.Math for some examples.
BigDecimal can represent any terminating decimal fraction exactly, given enough memory. That is very, very good in situations in which terminating decimal fractions have special status, such as many money calculations.
In addition to exact representation of terminating decimal fractions, it could also be used to get a closer approximation to e.g. one third than is possible with double. However, situations in which you need an approximation that is closer than double supplies are very rare. The closest double to one third is 0.333333333333333314829616256247390992939472198486328125, which is close enough for most practical purposes. Try measuring the difference between one third of an inch and 0.3333333333333333 inches.
BigDecimal is a only supported in software, does not have the support for mathematical functions that double has, and is much less space and time efficient.
If you have a job for which either would work functionally, use double. If you need exact representation of terminating decimal fractions, use BigDecimal.

Is BigDecimal an overkill in some cases?

I'm working with money so I need my results to be accurate but I only need a precision of 2 decimal points (cents). Is BigDecimal needed to guarantee results of multiplication/division are accurate?
BigDecimal is a very appropriate type for decimal fraction arithmetic with a known number of digits after the decimal point. You can use an integer type and keep track of the multiplier yourself, but that involves doing in your code work that could be automated.
As well as managing the digits after the decimal point, BigDecimal will also expand the number of stored digits as needed - many business and government financial calculations involve sums too large to store in cents in an int.
I would consider avoiding it only if you need to store a very large array of amounts of money, and are short of memory.
One common option is to do all your calculation with integer or long(the cents value) and then simply add two decimal places when you need to display it.
Similarly, there is a JODA Money library that will give you a more full-featured API for money calculations.
It depends on your application. One reason to use that level of accuracy is to prevent errors accumulated over many operations from percolating up and causing loss of valuable information. If you're creating a casual application and/or are only using it for, say, data entry, BigDecimal is very likely overkill.
+1 for Patricias answer, but I very strongly discourage anyone to implement own classes with an integer datatype with fixed bitlength as long as someone really do not know what you are doing. BigDecimal supports all rounding and precision issues while a long/int has severe problems:
Unknown number of fraction digits: Trade exchanges/Law/Commerce are varying in their amount
of fractional digits, so you do not know if your chosen number of digits must be changed and
adjusted in the future. Worse: There are some things like stock evaluation which need a ridiculous amount of fractional digits. A ship with 1000 metric tons of coal causes e.g.
4,12 € costs of ice, leading to 0,000412 €/ton.
Unimplemented operations: It means that people are likely to use floating-point for
rounding/division or other arithmetic operations, hiding the inexactness and leading to
all the known problems of floating-point arithmetic.
Overflow/Underflow: After reaching the maximum amount, adding an amount results in changing the sign. Long.MAX_VALUE switches to Long.MIN_VALUE. This can easily happen if you are doing fractions like (a*b*c*d)/(e*f) which may perfectly valid results in range of a long, but the intermediate nominator or denominator does not.
You could write your own Currency class, using a long to hold the amount. The class methods would set and get the amount using a String.
Division will be a concern no matter whether you use a long or a BigDecimal. You have to determine on a case by case basis what you do with fractional cents. Discard them, round them, or save them (somewhere besides your own account).

ArithmeticException thrown during BigDecimal.divide

I thought java.math.BigDecimal is supposed to be The Answer™ to the need of performing infinite precision arithmetic with decimal numbers.
Consider the following snippet:
import java.math.BigDecimal;
//...
final BigDecimal one = BigDecimal.ONE;
final BigDecimal three = BigDecimal.valueOf(3);
final BigDecimal third = one.divide(three);
assert third.multiply(three).equals(one); // this should pass, right?
I expect the assert to pass, but in fact the execution doesn't even get there: one.divide(three) causes ArithmeticException to be thrown!
Exception in thread "main" java.lang.ArithmeticException:
Non-terminating decimal expansion; no exact representable decimal result.
at java.math.BigDecimal.divide
It turns out that this behavior is explicitly documented in the API:
In the case of divide, the exact quotient could have an infinitely long decimal expansion; for example, 1 divided by 3. If the quotient has a non-terminating decimal expansion and the operation is specified to return an exact result, an ArithmeticException is thrown. Otherwise, the exact result of the division is returned, as done for other operations.
Browsing around the API further, one finds that in fact there are various overloads of divide that performs inexact division, i.e.:
final BigDecimal third = one.divide(three, 33, RoundingMode.DOWN);
System.out.println(three.multiply(third));
// prints "0.999999999999999999999999999999999"
Of course, the obvious question now is "What's the point???". I thought BigDecimal is the solution when we need exact arithmetic, e.g. for financial calculations. If we can't even divide exactly, then how useful can this be? Does it actually serve a general purpose, or is it only useful in a very niche application where you fortunately just don't need to divide at all?
If this is not the right answer, what CAN we use for exact division in financial calculation? (I mean, I don't have a finance major, but they still use division, right???).
If this is not the right answer, what CAN we use for exact division in financial calculation? (I mean, I don't have a finance major, but they still use division, right???).
Then I was in primary school1, they taught me that when you divide by 1 by 3 you get a 0.33333... i.e. a recurring decimal. Division of numbers represented in decimal form is NOT exact. In fact for any fixed base there will be fractions (the result of dividing one integer by another) that cannot be represented exactly as a finite precision floating point number in that base. (The number will have a recurring part ...)
When you do financial calculations involving division, you have to consider the what to do with a recurring fraction. You can round it up, or down, or to the nearest whole number, or something else, but basically you cannot just forget about the issue.
The BigDecimal javadoc says this:
The BigDecimal class gives its user complete control over rounding behavior. If no rounding mode is specified and the exact result cannot be represented, an exception is thrown; otherwise, calculations can be carried out to a chosen precision and rounding mode by supplying an appropriate MathContext object to the operation.
In other words, it is your responsibility to tell BigDecimal what to do about rounding.
EDIT - in response to these followups from the OP.
How does BigDecimal detect infinite recurring decimal?
It does not explicitly detect the recurring decimal. It simply detects that the result of some operation cannot be represented exactly using the specified precision; e.g. too many digits are required after the decimal point for an exact representation.
It must keep track of and detect a cycle in the dividend. It COULD HAVE chosen to handle this another way, by marking where the recurring portion is, etc.
I suppose that BigDecimal could have been specified to represent a recurring decimal exactly; i.e. as a BigRational class. However, this would make the implementation more complicated and more expensive to use2. And since most people expect numbers to be displayed in decimal, and the problem of recurring decimal recurs at that point.
The bottom line is that this extra complexity and runtime cost would be inappropriate for typical use-cases for BigDecimal. This includes financial calculations, where accounting conventions do not allow you to use recurring decimals.
1 - It was an excellent primary school. You may have been taught this in high school.
2 - Either you try to remove common factors of the divisor and dividend (computationally expensive), or allow them to grow without bounds (expensive in space usage and computationally expensive for subsequent operations).
The class is BigDecimal not BigFractional. From some of your comments it sounds like you just want to complain that someone didn't build in all possible number handling algorithms into this class. Financial apps do not need infinite decimal precision; just perfectly accurate values to the precision required (typically 0, 2, 4, or 5 decimal digits).
Actually I have dealt with many financial applications that use double. I don't like it but that was the way they are written (not in Java either). When there are exchange rates and unit conversions then there are both the potential of rounding and bruising problems. BigDecimal eliminates the later but there is still the former for division.
If you want to work with decimals, not rational numbers, and you need exact arithmetics before the final rounding (rounding to cents or something), here's a little trick.
You can always manipulate your formulas so that there's only one final division. That way you won't lose precision during calculations and you'll always get the correctly rounded result. For instance
a/b + c
equals
(a + bc) / b.
By the way, I'd really appreciate
insight from people who've worked with
financial software. I often heard
BigDecimal being advocated over double
In financial reports we use alwasy BigDecimal with scale = 2 and ROUND_HALF_UP, since all printed values in a report must be lead to a reproducable result. If someone checks this using a simple calculator.
In switzerland they round to 0.05 since they no longer have 1 or 2 Rappen coins.
You should prefer BigDecimal for finance calculations. Rounding should be specified by the business. E.g. an amount (100,00$) has to be split equally across three accounts. There has to be a business rule which account takes the extra cent.
Double, floats are not approriate for use in financial applications because they can not represent fractions of 1 precisely that are not exponentials of 2. E.g. consider 0.6 = 6/10 = 1*1/2 + 0*1/4 + 0*1/8 + 1*1/16 + ... = 0.1001...b
For mathematic calculations you can use a symbolic number, e.g. storing denominator and numerator or even a whole expression (e.g. this number is sqrt(5)+3/4). As this is not the main use case of the java api you won' find it there.
Is there a need for
a=1/3;
b=a*3;
resulting in
b==1;
in financial systems? I guess not. In financial systems it is defined, which roundmode and scale has to be used, when doing calculations. In some situations, the roundmode and scale is defined in the law. All components can rely on such a defined behaviour. Returning b==1 would be a failure, because it would not fulfill the specified behaviour. This is very important when calculating prices etc.
It is like the IEEE 754 specifications for representing floats in binary digits. A component must not optimize a "better" representation without loss of information, because this will break the contract.
To divide save, you have to set the MATHcontext,
BigDecimal bd = new BigDecimal(12.12, MathContext.DECIMAL32).divide(new BigDecimal(2)).setScale(2, RoundingMode.HALF_UP);
I accept that Java doesn't have great support for representing fractions, but you have to realise that it is impossible to keep things entirely precise when working with computers. At least in this case, the exception is telling you that precision is being lost.
As far as I know, "infinite precision arithmetic with decimal numbers" just isn't going to happen. If you have to work with decimals, what you're doing is probably fine, just catch the exceptions. Otherwise, a quick google search finds some interesting resources for working with fractions in Java:
http://commons.apache.org/math/userguide/fraction.html
http://www.merriampark.com/fractions.htm
Best way to represent a fraction in Java?
Notice we are using a computer... A computer has a lot of ram and precision takes ram. So when you want an infinite precision you need
(infinite * infinite) ^ (infinite * Integer.MAX_VALUE) terrabyte ram...
I know 1 / 3 is 0.333333... and it should be possible to store it in ram like "one divided by three" and then you can multiply it back and you should have 1. But I don't think Java has something like that...
Maybe you have to win the Nobel Price for writing something doing that. ;-)

Categories

Resources