aspose file tools*
The moose likes Java in General and the fly likes Why 100 * A * B * C is not same as A * B * C * 100 if A, B, C are double? Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Java » Java in General
Bookmark "Why 100 * A * B * C is not same as A * B * C * 100 if A, B, C are double?" Watch "Why 100 * A * B * C is not same as A * B * C * 100 if A, B, C are double?" New topic
Author

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

Ashik Uzzaman
Ranch Hand

Joined: Jul 05, 2001
Posts: 2370

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?


Ashik Uzzaman
Senior Member of Technical Staff, Salesforce.com, San Francisco, CA, USA.
Sunny Jain
Ranch Hand

Joined: Jul 23, 2007
Posts: 433

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)


Thanks and Regards,
SCJP 1.5 (90%), SCWCD 1.5 (85%), The Jovial Java, java.util.concurrent tutorial
Pat Farrell
Rancher

Joined: Aug 11, 2007
Posts: 4659
    
    5

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

Joined: Aug 16, 2005
Posts: 14432
    
  23

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.


Java Beginners FAQ - JavaRanch SCJP FAQ - The Java Tutorial - Java SE 8 API documentation
Pat Farrell
Rancher

Joined: Aug 11, 2007
Posts: 4659
    
    5

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

Joined: Oct 13, 2005
Posts: 40052
    
  28
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

Joined: Oct 30, 2001
Posts: 1970
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?"


Betty Rubble? Well, I would go with Betty... but I'd be thinking of Wilma.
Ashik Uzzaman
Ranch Hand

Joined: Jul 05, 2001
Posts: 2370

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

Joined: Aug 11, 2007
Posts: 4659
    
    5

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

Joined: Oct 13, 2005
Posts: 40052
    
  28
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

Joined: Jul 05, 2001
Posts: 2370

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

Joined: Oct 02, 2003
Posts: 11499
    
  16

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.


There are only two hard things in computer science: cache invalidation, naming things, and off-by-one errors
Campbell Ritchie
Sheriff

Joined: Oct 13, 2005
Posts: 40052
    
  28
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

    Joined: Oct 30, 2001
    Posts: 1970
    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

    Joined: Aug 11, 2007
    Posts: 4659
        
        5

    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

    Joined: Sep 17, 2006
    Posts: 1282
    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 ]

    "The differential equations that describe dynamic interactions of power generators are similar to that of the gravitational interplay among celestial bodies, which is chaotic in nature."
     
    I agree. Here's the link: http://aspose.com/file-tools
     
    subject: Why 100 * A * B * C is not same as A * B * C * 100 if A, B, C are double?