Java fast money representation? - java

I'm working on a real time application that deals with money in different currencies and exchange rates using BigDecimal, however I'm facing some serious performance issues and I want to change the underlying representation.
I've read again and again that a good and fast way of representing money in Java is by storing cents (or whatever the required precision is) using a long. As one of the comments pointed out, there are some libs with wrappers that do just that, such as FastMoney from JavaMoney.
Two questions here.
Is it always safe to store money as a long (or inside a wrapper) and keep everything else (like exchange rates) as doubles? In other words, won't I run into basically the same issues as having everything in doubles if I do Math.round(money * rate) (money being cents and rate being a double)?
FastMoney and many other libs only support operations between them and primitive types. How am I supposed to get an accurate representation of let's say the return of an investment if I can't do profit.divide(investment) (both being FastMoney). I guess the idea is I convert both to doubles and then divide them, but that would be inaccurate right?

The functionality you are looking for is already implemented in the JavaMoney Library.
It has a FastMoney class that does long arithmetic which is exactly what you have asked for.
For New Java Developers - Why long and not double?
Floating point arithmetic in Java leads to some unexpected errors in precision due to their implementation. Hence it is not recommended in financial calculations.
Also note that this is different from the precision loss in long arithmetic calculations which is due to the fractional portion not being stored in the long. This can be prevented during implementation by moving the fractional portion to another long (e.g. 1.05 -> 1 dollar and 5 cents).
References
A Quick Tutorial
Project Website

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.

When shall use float type in Java?

I know float type is A IEEE floating point, and it's not accuracy in calculation, for example, if I'd like to sum two floats 8.4 and 2.4, what I get is 10.7999999 rather than 10.8. I also know BigDecimal can solve this problem, but BigDecimal is much slower than float type.
In most real productions we'd like an accuracy value like above 10.8 not a 10.7999.. so my question is shall I prevent to use float as much as I can in programming? if not is there any use cases? I mean in a real production.
If you're handling monetary amounts, then numbers like 8.4 and 2.4 are exact values, and you'll want to use BigDecimal for those. However, if you're doing a physics calculation where you're dealing with measurements, the values 8.4 and 2.4 aren't going to be exact anyway, since measurements aren't exact. That's a use case where using double is better. Also, a scientific calculation could involve things like square roots, trigonometric functions, logarithms, etc., and those can be done only using IEEE floats. Calculations involving money don't normally involve those kinds of functions.
By the way, there's very little reason to ever use the float type; stick with double.
You use float when the percision is enough. It is generally faster to do calculations with float and requires less memory. Sometimes you just need the performance.
What you describe is caused by the fact that binary floating point numbers cannot exactly represent many numbers that can be exactly represented by decimal floating point numbers, like 8.4 or 2.4.
This affects not only the float type in Java but also double.
In many cases you can do calculations with integers and then rescale to get the deciamls correctly. But if you require numbers with equal relative accurracies, no matter how large they are, floating point is far superior.
So yes, if you can, you should prefer integers over floats, but there are many applications where floating point is required. This includes many scientific and mathematical algorithms.
You should also consider that 10.7999999 instead of 10.8 looks weird when displayed but actually the difference is really small. So it's not so much an accurracy issue but more related to number formatting. In most cases this problem is resolved by rounding the number appropriately when converting it to a string for output, for example:
String price = String.format("%.2f", floatPrice);
BigDecimals are very precise (you can determine their precision -- it is mainly limited by memory) but pretty slow and memory intensive. You use them when you need exact results, i.e. in financial applications, or when you otherwise need very precise results and when speed is not too critical.
Floating point types (double and float) are not nearly as precise, but much faster and they only take up limited memory. Typically, a float takes up 4 bytes and a double takes up 8 bytes. You use them with measurements that can't be very exact anyway, but also if you need the speed or the memory. I use them for (real time) graphics and real time music. Or when otherwise precision of the result is not so important, e.g. when measuring time or percentages when downloading or some such.

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.

Using the right numeric data type

After becoming more engaged with training new engineers as well as reading Jon Skeet's DevDays presentation I have begun to recognize many engineers aren't clear when to use which numeric datatypes when. I appreciate the role a formal computer science degree plays in helping with this, but I see a lot of new engineers showing uncertainty because they have never worked with large data sets, or financial software, or programming phyiscs or statistics problems, or complex datastore issues.
My experience is that people really grok concepts when they are explained within context. I am looking for good examples of real programming problems where certain data is best represented using data type. Try to stay away from the textbook examples if possible. I am tagging this with Java, but feel free to give examples in other languages and retag:
Integer, Long, Double, Float, BigInteger, etc...
I really don't think you need examples or anything complex. This is simple:
Is it a whole number?
Can it be > 2^63? BigInteger
Can it be > 2^31? long
Otherwise int
Is it a decimal number?
Is an approximate value ok?
double
Does it need to be exact? (example: monetary amounts!)
BigDecimal
(When I say ">", I mean "greater in absolute value", of course.)
I've never used a byte or char to represent a number, and I've never used a short, period. That's in 12 years of Java programming. Float? Meh. If you have a huge array and you are having memory problems, I guess.
Note that BigDecimal is somewhat misnamed; your values do not have to be large at all to need it.
BigDecimal is the best when it comes to maintaining accurate floating point calculations, and being able to specify the desired accuracy. I believe float (and to some extent double) offer performance benefits over BigDecimal, but at the cost of accuracy and usability.
One important point you might want to articulate is that it's almost always an error to compare floating-point numbers for equality. For example, the following code is very likely to fail:
double euros = convertToEuros(item.getCostInDollars());
if (euros == 10.0) {
// this line will most likely never be reached
}
This is one of many reasons why you want to use discrete numbers to represent currency.
When you absolutely must compare floating-point numbers, you can only do so approximately; something to the extent of:
double euros = convertToEuros(item.getCostInDollars());
if (Math.abs(euros - 10.0) < EPSILON) {
// this might work
}
As for practical examples, my usual rule of thumb is something like this:
double: think long and hard before using it; is the pain worth it ?
float: don't use it
byte: most often used as byte[] to represent some raw binary data
int: this is your best friend; use it to represent most stuff
long: use this for timestamps and database IDs
BigDecimal and BigInteger: if you know about these, chances are you know what you're doing already, so you don't need my advice
I realize that these aren't terribly scientific rules of thumb, but if your target audience are not computer scientists, it might be best to stick to basics.
normally numeric if we're talking machine independenat (32/64bit) data type size are as below,
integer: 4 bytes
long: 8 bytes
decimal/float: 4bytes
double : 8bytes
and the sizes reduced to half for signed values (eg: for 4bytes, unsigned=4billions, signed=2billions)
bigInt (depends on language implementation) sometimes up to 10bytes.
for high volumes data archiving (such as search engine) i would highly recommended byte and short to save spaces.
byte: 1 byte, (0-256 unsigned, -128 - 128 signed)
short: 2 byte (65k unsigned)
let's say you want to save record about AGE, since nobody ever lives over 150, so you used data type BYTE (read above for size) but if you use INTEGER you already wasted extra 3bytes and seriously tell me wth live over 4billions yrs.
VInt's in Lucene are the devil. The small benefit in size is outweighed hugely by the performance penalty in reading them byte-by-byte.
A good thing to talk about is the space versus time trade off. Saving 200mb was great in 1996, but in 2010, thrashing IO buffers reading a byte at a time is terrible.

Categories

Resources