Velocity Reviews > Java > BigDecimal and double arithmetic problems

# BigDecimal and double arithmetic problems

Ramon
Guest
Posts: n/a

 11-02-2008
Hi,

I had first a problem when using double primitive data type. I've tried
to add to double numbers but the result was technically incorrect. Here
is a snippet that was taken from the program:

double a = -0.7;
double b = 0.2;
System.err.println( a + b ); // outputs -0.49999999999999994 instead of -0.5

I've also tried to use BigDecimal but still no luck. Here is part of
the program:

BigDecimal a = new BigDecimal(-0.7);
BigDecimal b = new BigDecimal(0.2);
System.err.println( a.add(b) ); // unprecise output

So, my question is: Is there a way to perform an accurate addition of
-0.7 and 0.2 in Java?

Thanks.

Martin Gregorie
Guest
Posts: n/a

 11-02-2008
On Sun, 02 Nov 2008 14:06:48 +0100, Ramon wrote:

> Hi,
>
> I had first a problem when using double primitive data type. I've tried
> to add to double numbers but the result was technically incorrect. Here
> is a snippet that was taken from the program:
>
> double a = -0.7;
> double b = 0.2;
> System.err.println( a + b ); // outputs -0.49999999999999994 instead of
> -0.5
>

This is scarcely surprising: its extremely unlikely that double can
represent either literal exactly. This isn't Java-specific - any
programming language will do the same.

Programs must be written to recognise this fact:

if (a == b) // WRONG
if (Math.abs(a - b) < 0.01) // RIGHT

but in the second example the acceptable difference (0.01 in this case)
depends on the precision of the numbers you're calculating with.
Similarly, you may need to round output values when you format them.

If you don't know this then you don't understand floating point numbers.

--
martin@ | Martin Gregorie
gregorie. | Essex, UK
org |

Joshua Cranmer
Guest
Posts: n/a

 11-02-2008
Ramon wrote:
> Hi,
>
> I had first a problem when using double primitive data type. I've tried
> to add to double numbers but the result was technically incorrect. Here
> is a snippet that was taken from the program:
>
> double a = -0.7;
> double b = 0.2;
> System.err.println( a + b ); // outputs -0.49999999999999994 instead
> of -0.5

Actually, the result is more correct than you think it is. A computer
cannot store 0.7 or 0.2 accurately; what it instead stores is a number
that is correct to within 2^-53 (at least for double types).

Adding -0.7 + 0.2 is actually therefore adding two numbers who are
within 2^-53 of those numbers, so the result is within 2^-52 of -0.5. In
this case, the answer is not as close as it could be to -0.5--off by the
last binary digit, in fact.

So, it is in fact technically correct once you understand what the
computer is really doing.

> I've also tried to use BigDecimal but still no luck. Here is part of
> the program:
>
> BigDecimal a = new BigDecimal(-0.7);
> BigDecimal b = new BigDecimal(0.2);
> System.err.println( a.add(b) ); // unprecise output

It's not imprecise. It's doing [the binary representation of -0.7 within
2^-53] + [the binary representation of 0.2 within 2^-53] without losing
any precision: it treats each approximate number as being perfectly
precise, and, as such, returns a more precise version of the output.

Note that the loss in precision occurs at compile-time by merely writing
-0.7. Java will store the closest double representation to -0.7, which
is what BigDecimal is treating as an infinitely-precise number. If you
want a more precise representation, you have to give it in a that isn't
translated by the Java compiler... maybe you might want a String?

> So, my question is: Is there a way to perform an accurate addition of
> -0.7 and 0.2 in Java?

The number is accurate to within 2^-52, which gives it an error of about
2^-51. I'd say that's accurate enough for me.

--
Beware of bugs in the above code; I have only proved it correct, not
tried it. -- Donald E. Knuth

Ramon
Guest
Posts: n/a

 11-02-2008
Martin Gregorie wrote:
> This is scarcely surprising: its extremely unlikely that double can
> represent either literal exactly. This isn't Java-specific - any
> programming language will do the same.
>
> Programs must be written to recognise this fact:
>
> if (a == b) // WRONG
> if (Math.abs(a - b) < 0.01) // RIGHT
>
> but in the second example the acceptable difference (0.01 in this case)
> depends on the precision of the numbers you're calculating with.
> Similarly, you may need to round output values when you format them.
>
> If you don't know this then you don't understand floating point numbers.
>
>

Yes I know that the mother of all problems is the CPU's floating point
numerical system. But is there a way how one can add -0.7 with 0.2 and
the answer is exactly -0.5?

Arne Vajhøj
Guest
Posts: n/a

 11-02-2008
Ramon wrote:
> Martin Gregorie wrote:
>> This is scarcely surprising: its extremely unlikely that double can
>> represent either literal exactly. This isn't Java-specific - any
>> programming language will do the same.
>> Programs must be written to recognise this fact:
>>
>> if (a == b) // WRONG
>> if (Math.abs(a - b) < 0.01) // RIGHT
>>
>> but in the second example the acceptable difference (0.01 in this
>> case) depends on the precision of the numbers you're calculating with.
>> Similarly, you may need to round output values when you format them.
>>
>> If you don't know this then you don't understand floating point numbers.
>>
>>

>
> Yes I know that the mother of all problems is the CPU's floating point
> numerical system. But is there a way how one can add -0.7 with 0.2 and
> the answer is exactly -0.5?

Try with BigDecimal *and* use the construtor that takes a String
as argument instead of the one that takes a double.

Arne

Lew
Guest
Posts: n/a

 11-02-2008
Ramon wrote:
> I had first a problem when using double primitive data type. I've tried
> to add to double numbers but the result was technically incorrect. Here
> is a snippet that was taken from the program:
>
> double a = -0.7;
> double b = 0.2;
> System.err.println( a + b ); // outputs -0.49999999999999994 instead
> of -0.5

<http://docs.sun.com/source/806-3568/ncg_goldberg.html>

--
Lew

Lew
Guest
Posts: n/a

 11-02-2008
Ramon wrote:
> Yes I know that the mother of all problems is the CPU's floating point
> numerical system. But is there a way how one can add -0.7 with 0.2 and
> the answer is exactly -0.5?

In decimal arithmetic accurate to, say, 6 places, is there a way to add 1/3
and 1/7 so the answer is exactly 10/21?

--
Lew

Ramon
Guest
Posts: n/a

 11-02-2008
Arne Vajhøj wrote:
> Try with BigDecimal *and* use the construtor that takes a String
> as argument instead of the one that takes a double.
>
> Arne

That did the trick. Thanks Arne!

John B. Matthews
Guest
Posts: n/a

 11-02-2008
In article <gekc6m\$2n5\$(E-Mail Removed)>, Lew <(E-Mail Removed)> wrote:

> Ramon wrote:
> > Yes I know that the mother of all problems is the CPU's floating point
> > numerical system. But is there a way how one can add -0.7 with 0.2 and
> > the answer is exactly -0.5?

>
> In decimal arithmetic accurate to, say, 6 places, is there a way to add 1/3
> and 1/7 so the answer is exactly 10/21?

An excellent rhetorical question, as it suggests rational arithmetic as
one approach to the OP's problem:

<http://jscience.org/api/org/jscience/mathematics/number/Rational.html>

<code>
import org.jscience.mathematics.number.Rational;

public class RationalTest {

public static void main(String[] args) {
Rational a = Rational.valueOf(-7, 10);
Rational b = Rational.valueOf(2, 10);
Rational sum = a.plus(b);
System.out.println(sum);
System.out.println(sum.doubleValue());
a = Rational.valueOf(1, 3);
b = Rational.valueOf(1, 7);
sum = a.plus(b);
System.out.println(sum);
System.out.println(sum.doubleValue());
}
}
</code>
<console>
-1/2
-0.5
10/21
0.47619047619047616
<.console>
--
John B. Matthews
trashgod at gmail dot com
http://home.roadrunner.com/~jbmatthews/

Hal Rosser
Guest
Posts: n/a

 11-03-2008

"Ramon" <(E-Mail Removed)> wrote in message
news:gek8l4\$nv8\$(E-Mail Removed)...
> Hi,
> BigDecimal a = new BigDecimal(-0.7);
> BigDecimal b = new BigDecimal(0.2);
> System.err.println( a.add(b) ); // unprecise output
>
> So, my question is: Is there a way to perform an accurate addition
> of -0.7 and 0.2 in Java?

Yes,
Use the BigDecimal constructor that accepts a String
In other words, put quotes around the args

BigDecimal a = new BigDecimal("-0.7");
BigDecimal b = new BigDecimal("0.2");

System.out.println(s.add(b));

This will give ya the exactness for which you search.

the way you did it, the impreciseness of the double is used to create the
BigDecimal objects,
but this way, its exact. Using the String arg usually works better for
BigDecimal.

Hope this helps

 Thread Tools

 Posting Rules You may not post new threads You may not post replies You may not post attachments You may not edit your posts BB code is On Smilies are On [IMG] code is On HTML code is OffTrackbacks are On Pingbacks are On Refbacks are Off Forum Rules

 Similar Threads Thread Thread Starter Forum Replies Last Post Stanimir Stamenkov Java 4 07-18-2008 10:49 AM czarnysfetr@gmail.com Java 3 02-05-2007 02:49 PM M.-A. Lemburg Python 3 04-04-2005 01:59 PM Sydex C++ 12 02-17-2005 06:30 PM Forrest Hump Java 4 08-22-2003 03:53 PM

Advertisments