Problem with a double

P

Patricia Shanahan

Roedy said:
It is one of the most commonly asked questions. See
http://mindprod.com/jgloss/floatingpoint.html

I don't think anyone really understands the claimed output, 0.399999999
as the result of adding ((0 + 0.2) + 0.2).

The relative error is a million times too large to be explained by
double precision rounding on adding two numbers of similar magnitude and
equal sign. In any case, in IEEE 754 binary floating point, 0.4 has the
same representation as the result of adding the representation of 0.2 to
itself, so the String answer should have been "0.4".

I am concerned about the fuzz-inserting demon model, because it causes
people to accept as rounding error results that have to have a
different, as yet unknown, cause.

Patricia
 
R

Roedy Green

The relative error is a million times too large to be explained by
double precision rounding on adding two numbers of similar magnitude and
equal sign. In any case, in IEEE 754 binary floating point, 0.4 has the
same representation as the result of adding the representation of 0.2 to
itself, so the String answer should have been "0.4".

I have added a point to the entry at
http://mindprod.com/jgloss/floatingpoint.html. Is this what you were
referring to?

"When numbers are converted from float or double to String for display
they may be truncated. Further the process of converting from binary
to decimal introduces even more errors that were not in the original
computation result, possibly because of repeaters -- fractions that
cannot be represented exactly in binary or decimal."
 
R

Roedy Green

I have an amazing problem with a double in Java.

What version of Java are you using? What hardware are you running it
on?

Could you also post your complete code.
 
M

Mark Thornton

Patricia said:
I don't think anyone really understands the claimed output, 0.399999999
as the result of adding ((0 + 0.2) + 0.2).

The relative error is a million times too large to be explained by
double precision rounding on adding two numbers of similar magnitude and
equal sign. In any case, in IEEE 754 binary floating point, 0.4 has the
same representation as the result of adding the representation of 0.2 to
itself, so the String answer should have been "0.4".

I am concerned about the fuzz-inserting demon model, because it causes
people to accept as rounding error results that have to have a
different, as yet unknown, cause.

Patricia

Far too many programmers treat floating point as a no go area or "here
be dragons".

Mark Thornton
 
M

Mark Thornton

Roedy said:
I have added a point to the entry at
http://mindprod.com/jgloss/floatingpoint.html. Is this what you were
referring to?

"When numbers are converted from float or double to String for display
they may be truncated. Further the process of converting from binary
to decimal introduces even more errors that were not in the original
computation result, possibly because of repeaters -- fractions that
cannot be represented exactly in binary or decimal."

No, I think that is an example what Patricia does NOT like. The
conversion of floating point values to string is very precisely defined
in Java. Your statement gives the impression of unbounded error which is
very much not the case.

Mark Thornton
 
P

Patricia Shanahan

Mark said:
No, I think that is an example what Patricia does NOT like. The
conversion of floating point values to string is very precisely defined
in Java. Your statement gives the impression of unbounded error which is
very much not the case.
....

Indeed. Dismissing the anomalous result as being floating point rounding
error stands in the way of finding out what is really going wrong in the
OP's program. Maybe it is just a matter of confusion between two
versions, in which case it does not matter. However, there could be a
real bug that is being masked.

More generally, the fuzz-inserting demon model could have two bad
consequences:

1. Acceptance of bugs as being due to rounding error.

2. Non-use of floating point when it would be the best choice, because
of uncomprehending fear of rounding error.

Patricia
 
G

George Neuner

George Neuner wrote:
...

I get 0.40000000000000002220446049250313080847263336181640625

Patricia

IEEE double precision has only 17 significant decimal figures. Are
you calculating that on a VAX?

George
 
S

Stefan Ram

George Neuner said:
IEEE double precision has only 17 significant decimal figures.

I assume, what she does is showing you
the insignificant decimal figures, too.
 
P

Patricia Shanahan

George said:
IEEE double precision has only 17 significant decimal figures. Are
you calculating that on a VAX?

new BigDecimal(0.4).toString()

"new BigDecimal(someDouble) returns a BigDecimal whose value is exactly
the value of the double. BigDecimal's toString() is also exact.

Although double has about the same precision as 16 significant decimal
digit arithmetic, the doubles do not align with the short decimal
numbers. Any numeric double can be exactly represented as a decimal
fraction, but it often takes a lot more than 17 digits.

Patricia
 
G

George Neuner

...

We certainly agree on the bottom line, that the final String answer
should be "0.4". I am confused about whether you are agreeing or
disagreeing with my analysis leading to that conclusion. Could you clarify?

Patricia

It wasn't clear from your post (and still isn't) whether you were
referring to binary rounding in the arithmetic or decimal rounding in
the print formatting. The "correct" answer of 0.4 should be due to
decimal rounding because the default is to include 6 significant
figures (which should be 0.40000) and to truncate trailing zeros.

I agree that either rounding doesn't explain the OP's strange results.
However, I must point out that the OP did not mention what platform
(CPU + JVM) he was using, and even though the Java spec requires
IEEE-754 arithmetic, in fact no FPU hardware is completely 754
compliant - to achieve compliance some amount of software emulation is
always necessary.

I can only speculate that the OP is using a platform that is farther
from 754 compliance than that of the average Java user.


As for the rest, I was taking the opportunity to explain a bit more
about floating point to make clear that floating point numbers are not
like the real numbers we learned about in school. It wasn't aimed at
you specifically but more for general consumption.

George
 
S

Stefan Ram

George Neuner said:
the default is to include 6 significant figures

public class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println( java.lang.Math.atan2( 1.0, 1.0 )* 4.0 ); }}

3.141592653589793
 
P

Patricia Shanahan

George said:
It wasn't clear from your post (and still isn't) whether you were
referring to binary rounding in the arithmetic or decimal rounding in
the print formatting. The "correct" answer of 0.4 should be due to
decimal rounding because the default is to include 6 significant
figures (which should be 0.40000) and to truncate trailing zeros.

I think possibly you are confusing println with printf?

The conversion applied is equivalent to Double.toString(double). See
http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Double.html#toString(double)

The basic rule is "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."

There is nothing at all special about 6 digits for println.
I agree that either rounding doesn't explain the OP's strange results.
However, I must point out that the OP did not mention what platform
(CPU + JVM) he was using, and even though the Java spec requires
IEEE-754 arithmetic, in fact no FPU hardware is completely 754
compliant - to achieve compliance some amount of software emulation is
always necessary.

The JLS has detailed rules for floating point arithmetic. Absent
"strictfp", the rules allow for extra precision in some cases. I have
yet to see Java produce lower precision than is specified. In this
particular case, the hardware would have to be *very* weird to avoid
getting the right answer.

Patricia
 
G

George Neuner

I think possibly you are confusing println with printf?

Oops ... you're right. Going back and forth between languages gets
confusing sometimes.

The JLS has detailed rules for floating point arithmetic.

That's true. However if you look at JavaME, you'll see that ME
platforms are allowed to implement subsets of Java and even to bend
rules for what they do implement.

George
 
G

George Neuner

new BigDecimal(0.4).toString()

"new BigDecimal(someDouble) returns a BigDecimal whose value is exactly
the value of the double. BigDecimal's toString() is also exact.

Although double has about the same precision as 16 significant decimal
digit arithmetic, the doubles do not align with the short decimal
numbers. Any numeric double can be exactly represented as a decimal
fraction, but it often takes a lot more than 17 digits.

That's cheating ;)

BigDecimals don't have the same semantics as hardware FP. If you have
enough bits you can represent any real number - not just the subset
also representable by IEEE double precision numbers. In any event, we
were discussing fractions representable in 52 bits.

George
 
P

Patricia Shanahan

George said:
That's cheating ;)

BigDecimals don't have the same semantics as hardware FP. If you have
enough bits you can represent any real number - not just the subset
also representable by IEEE double precision numbers. In any event, we
were discussing fractions representable in 52 bits.

The number I posted is the *exact* decimal representation of a number
that, as a binary fraction, can be represented in 53 bits.

Think about e.g. 1/8. As a binary fraction, 0.001, it has one non-zero
digit. As a decimal fraction, 0.125, it has three non-zero digits. The
fact that a number can be represented with a 53 bit binary mantissa is
not sufficient to ensure it can be represented in 53 decimal digits, let
alone 17.

Note that normalized Java doubles really have 53 bits of mantissa,
despite only having space for 52 mantissa bits. The leading digit of the
mantissa is a non-zero binary digit, so storing it would be a waste of
space.

It is not true that "if you have enough bits you can represent any real
number". There are more real numbers than there are finite length bit
sequences.

Patricia
 
M

Mark Thornton

Patricia said:
The JLS has detailed rules for floating point arithmetic. Absent
"strictfp", the rules allow for extra precision in some cases. I have
yet to see Java produce lower precision than is specified. In this
particular case, the hardware would have to be *very* weird to avoid
getting the right answer.

Actually I don't think extra precision is allowed. What is permitted,
without strictfp, is a larger exponent.

Mark Thornton
 
P

Patricia Shanahan

Mark said:
Actually I don't think extra precision is allowed. What is permitted,
without strictfp, is a larger exponent.

A wider exponent can lead to increased precision, by avoiding underflow
in intermediate results.

Patricia
 
L

Lew

Patricia said:
It is not true that "if you have enough bits you can represent any real
number". There are more real numbers than there are finite length bit
sequences.

Aleph-1 is greater than Aleph-0.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top