LOSS OF PRECISION IN DOUBLE TYPE

Hi everybody,

I'm developing a Point of Sale (POS) module of an ERP system and I noticed a very weird behavior regarding the double type:

What齭 the result of?

double ops = 71.1 * 100 (or 71.1 * 100.0 ?doesn齮 matter)

One will say: ops = 7110.0but what we really get is ops = 7109.9999999999 (!!!!)

In a context of a POS application (dealing with money) this can cause some serious trouble?

So does anyone experienced this problem or know the explanation for this behavior? Is that a bug in JVM or it齭 just an 齟xpected?loss of precision situation caused by the internal representation of double variables or whatever?br>

I gotta tell that my tests were made on a j2sdk1.4.2_04 and that this happens only with some very specific numbers (the other case I got was 36.8 * 100).

Thanks for any help!!

[850 byte] By [AdrianoNobre] at [2007-9-30 19:50:13]
# 1
This is how binary numbers work with decimal representations. You should use the BigDecimal class instead./Kaj
kajbj at 2007-7-7 0:37:43 > top of Java-index,Java Essentials,Java Programming...
# 2

First of all, don't use all caps in the title, it makes you look like a *****.

> So does anyone experienced this problem or know the

> explanation for this behavior?

Yes, everyone.

> Is that a bug in JVM or it齭 just an expected loss of precision situation

> caused by the internal representation of double variables or whatever

The latter one.

-Kayaman- at 2007-7-7 0:37:43 > top of Java-index,Java Essentials,Java Programming...
# 3
[url= http://java.sun.com/developer/JDCTechTips/2003/tt0204.html#2]SOME THINGS YOU SHOULD KNOW ABOUT FLOATING-POINT ARITHMETIC[/url][url= http://docs.sun.com/source/806-3568/ncg_goldberg.html]What Every Computer Scientist Should Know About Floating-Point Arithmetic[/url]
yawmark at 2007-7-7 0:37:43 > top of Java-index,Java Essentials,Java Programming...
# 4

The problem is that not all decimal numbers have an exact floating point representation.

If you're handling money you're better of using integers like int or long. You convert all money amounts to the smallest monetary unit, like instead of 1.05 dollars you use 105 cents. Then +, - and * will be exact and you don't lose a cent. When you perform / you have to be careful and ask the accountants how to round (there are rules for that).

An alternative is to use BigDecimal. It uses integers internally to represent fractional numbers but may be slower than using int or long directly like above.

UlrikaJ at 2007-7-7 0:37:43 > top of Java-index,Java Essentials,Java Programming...
# 5

First of all thanks for the replies and sorry for the upper case in the tittle :-) (I was expecting that my request would be more "visible" like this... at least it worked (I got some answers).

Well, I knew the floating point representation (IEEE 754) for decimal numbers has problems of precision (or rounding error). What I found funny is that if we do the following 71.1f * 100.0f we'll get the right (or excepted) result, but for 71.1d * 100.0d we'll get a rounding error... So, for a less precise type (float) we'll get the right result and for a more precise type (double) we'll get a non-expected result ?!! (at least for this very "71.1 * 100" case)

But it's just a comment... I will use BigDecimal for my currency values...

Many thanks.

AdrianoNobre at 2007-7-7 0:37:43 > top of Java-index,Java Essentials,Java Programming...
# 6

Firstly, I don't think it's technically loss of precision, since the precision is unchanged. Secondly, the fact that floats appear to give the right result (which they don't internally, of course) is due to the way in which the number of decimal places to display is determined. The following is a quote from the API doc for Double.toString(double):

> How many digits must be printed for the fractional part of m or a? There must be at least one digit to represent the fractional

> part, and beyond that as many, but only as many, more digits as are needed to uniquely distinguish the argument value from

> adjacent values of type double. That is, suppose that x is the exact mathematical value represented by the decimal

> representation produced by this method for a finite nonzero argument d. Then d must be the double value nearest to x; or if

> two double values are equally close to x, then d must be one of them and the least significant bit of the significand of d must be 0.

Because float values are further apart than double values, fewer digits are used when displaying them in decimal.

YATArchivist at 2007-7-7 0:37:43 > top of Java-index,Java Essentials,Java Programming...
# 7

> What I found funny is that if we do

> the following 71.1f * 100.0f we'll get the right (or

> excepted) result, but for 71.1d * 100.0d we'll get a

> rounding error... So, for a less precise type (float)

> we'll get the right result and for a more precise type

> (double) we'll get a non-expected result ?!!

That's because your expectations are built on the wrong assumption that all all decimal numbers have an exact floating point representation. Try 71.125 instead. It's a number that lives up to your expectations. -:)

UlrikaJ at 2007-7-7 0:37:43 > top of Java-index,Java Essentials,Java Programming...