• Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

Why 100 * A * B * C is not same as A * B * C * 100 if A, B, C are double?

 
Ashik Uzzaman
Ranch Hand
Posts: 2373
Eclipse IDE Firefox Browser Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
This is the regarding the precision/scale issue with java's double values. I am trying to understand why 100 * A * B * C is not same as A * B * C * 100 if A, B, C are double values. Here is a code snippet to observe the case.



The output for the following code snippet is like -

aValue * bValue * cValue = 9127.335
multiplicationResult = 9127.335
aValue * bValue * cValue * 100 = 912733.4999999999
multiplicationResult = 912733.4999999999
100 * aValue * bValue * cValue = 912733.5
multiplicationResult = 912733.5

Why is it different and how can I make them behave as same whether mupltiply 100 at the beginning or at the end of the calculation?
 
Deepak Chopra
Ranch Hand
Posts: 433
Eclipse IDE Firefox Browser Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
This sound very interesting, I think the reason may be you are multiplying an integer with double in first case going from left to right:

double * double * double * int

so its equivalent to (double*double*double)*int

I think we are losing some precision when we are multiplying double(64 bit) with int(32 bit)


second case
int*double*double*double

so overall first int is getting multiplied with double..you can try something like this:

100*(a*b*c)
 
Pat Farrell
Rancher
Posts: 4678
7
Linux Mac OS X VI Editor
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Originally posted by Ashik Uzzaman:

multiplicationResult1 = 912733.4999999999
multiplicationResult2 = 912733.5



Because you are using floating point.
They are the same according to the rules of floating point.

The proper way to compare floats and doubles is


If you want it to work like money, don't use float, use BigDecimal
 
Jesper de Jong
Java Cowboy
Saloon Keeper
Posts: 15216
36
Android IntelliJ IDE Java Scala Spring
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The float and double data types do not have infinite precision, so you can expect rounding errors to occur.

Note that 912733.4999999999 and 912733.5 are practically the same number. The difference between those numbers is 0.00000000001.

If such small differences are important to you, you shouldn't use the double data type. Use BigDecimal instead, which gives you arbitrary precision.
 
Pat Farrell
Rancher
Posts: 4678
7
Linux Mac OS X VI Editor
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Originally posted by Jesper Young:

Note that 912733.4999999999 and 912733.5 are practically the same number.


In the float/double world, they are the same.
You can't tell how long the 9999 repeats, what we see printed is just the convenient output of the print formatter, not the actual value internally.

If there is no meaningful difference, they are the same.

Sometimes I wish that languages didn't have float/double, they are constantly misused.
 
Campbell Ritchie
Sheriff
Posts: 48652
56
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Originally posted by Pat Farrell:
You can't tell how long the 9999 repeats.
Yes, you can. Pass it to the constructor of a BigDecimal and print out the BigDecimal unformatted.



It just goes to show how imprecise floating-point is.

The reason floating-point arithmetic is useful is that there are people like engineers who used to use slide rules (I still have one myself), and they don't care whether they get a result of breakingStrain = 24.9 or 25; they will engineer to withstand 30 regardless! Using BigDecimal for that sort of calculation would necessitate specifying precision and rounding convention for division, and there would be a performance overhead.
 
Peter Chase
Ranch Hand
Posts: 1970
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
If you want a language that's only good for simple text-processing, simple financial calculations etc, sure you could do without floating-point. But Java is supposed to be a general-purpose language.

To be general-purpose, a language must be able to support the significant minority of applications that do serious maths, with numbers of widely-varying magnitude. This includes many types of graphics, printing, modelling of physical processes and even some types of games.

For numbers of widely-varying magnitude, you can't sensibly use integer types, because, while you can include an implicit scale factor, that scale factor has to be fixed.

You can use things like BigDecimal for widely-varying magnitudes, but calculations in BigDecimal are much slower, and take far more memory, than they do with floating-point. Sometimes, that doesn't matter, but in plenty of cases it does.

Perhaps, the compiler needs a "Clippy" that springs up and says: -

"I see you're using floating-point. Would you like some help with that?"
 
Ashik Uzzaman
Ranch Hand
Posts: 2373
Eclipse IDE Firefox Browser Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thank you so much for all your useful responses. So other than using BigDecimal, one way to get the constant result back is to use parenthesis correctly and in order. Although we don't know the order often, but it's at least a clue for me. Here are output of some calculations done by JVM -
 
Pat Farrell
Rancher
Posts: 4678
7
Linux Mac OS X VI Editor
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Originally posted by Ashik Uzzaman:
So other than using BigDecimal, one way to get the constant result back is to use parenthesis correctly and in order.


Sorry, this is incorrect. For your example problem, proper use of parenthesis can "fix" the problem, but for another set of numbers, or different terms, it will still be "wrong"

The problem is fundamental to floating point, and double. It can not be solved in general, other than saying "don't use floating point" in cases where precision is expected. Floating point was designed for engineering. It works great there.
 
Campbell Ritchie
Sheriff
Posts: 48652
56
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Originally posted by Peter Chase:
Perhaps, the compiler needs a "Clippy" that springs up and says: -

"I see you're using floating-point. Would you like some help with that?"
 
Ashik Uzzaman
Ranch Hand
Posts: 2373
Eclipse IDE Firefox Browser Java
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The following one will give me a constant result no matter what the parenthesis placement is. This might solve my problem, at least partially.

 
fred rosenberger
lowercase baba
Bartender
Pie
Posts: 12100
30
Chrome Java Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
one of the assignments on the CattleDrive has you simply loop 1000 times and add 0.1 each time. the result is NOT 100. there is no order to change, and you will never get the mathematically 'correct' result.
 
Campbell Ritchie
Sheriff
Posts: 48652
56
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Originally posted by Ashik Uzzaman:
The following one will give me a constant result no matter what the parenthesis placement is. This might solve my problem, at least partially.
That works in the present case, but in future if you want precision in arithmetic you can
  • Use BigDecimal, with String parameters to the constructor: new BigDecimal("123.45");
  • Use integer arithmetic, eg denominating money in pence, cents, etc.
  • A BigDecimal with a double argument will simply perpetuate the imprecision in the double.
     
    Peter Chase
    Ranch Hand
    Posts: 1970
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Originally posted by Campbell Ritchie:
    A BigDecimal with a double argument will simply perpetuate the imprecision in the double.


    Indeed. It's worse than that, in the example above, though. The BigDecimal constructor is being called with a "double" expression as an argument. The setScale() method is then being used to gloss over the resulting mess.

    Euyukk! Wrong!

    If you want guaranteed total accuracy, floating point must not appear anywhere in the calculation.
     
    Pat Farrell
    Rancher
    Posts: 4678
    7
    Linux Mac OS X VI Editor
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Use integer (with implied cents, pence, etc.) or fixed point arithemtic which looks a lot like integer.

    You can't use float or double and get what you want. See upthread suggest for a trivial test.

    Float considered harmful
     
    Nicholas Jordan
    Ranch Hand
    Posts: 1282
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    When the precision setting is not 0, the rules of BigDecimal arithmetic are broadly compatible with selected modes of operation of the arithmetic defined in ANSI X3.274-1996 and ANSI X3.274-1996/AM 1-2000 (section 7.4).


    RE:  :
    Originally posted by Pat Farrell:
    Use integer (with implied cents, pence, etc.) or fixed point arithemtic which looks a lot like integer.(...snip...)


    Source: Comemnts in source code for BigDecimal.
    [ May 31, 2008: Message edited by: Nicholas Jordan ]
     
    • Post Reply
    • Bookmark Topic Watch Topic
    • New Topic