Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Java > BigDecimal and double arithmetic problems

Reply
Thread Tools

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.
 
Reply With Quote
 
 
 
 
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 |
 
Reply With Quote
 
 
 
 
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
 
Reply With Quote
 
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?
 
Reply With Quote
 
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
 
Reply With Quote
 
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
 
Reply With Quote
 
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
 
Reply With Quote
 
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!
 
Reply With Quote
 
John B. Matthews
Guest
Posts: n/a
 
      11-02-2008
In article <gekc6m$2n5$>, Lew <> 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/
 
Reply With Quote
 
Hal Rosser
Guest
Posts: n/a
 
      11-03-2008

"Ramon" <> wrote in message
news:gek8l4$nv8$...
> 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


 
Reply With Quote
 
 
 
Reply

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 Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
BigDecimal(String) vs. BigDecimal(double) [Floating-point arithmetics] Stanimir Stamenkov Java 4 07-18-2008 10:49 AM
BigDecimal to power of BigDecimal czarnysfetr@gmail.com Java 3 02-05-2007 02:49 PM
Re: ANN: BigDecimal - decimal arithmetic on very large intergers M.-A. Lemburg Python 3 04-04-2005 01:59 PM
cannot convert parameter from 'double (double)' to 'double (__cdecl *)(double)' error Sydex C++ 12 02-17-2005 06:30 PM
Problem with Double to BigDecimal Conversion Forrest Hump Java 4 08-22-2003 03:53 PM



Advertisments
 



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57