Floating-point promotion behaviour.

G

Gabriele

Hi everybody. I have a question about floating point promotion.
Given the following code:

public static void main(String[] args) {
double b = 9.2f;
System.out.println(b);
}

could someone explain to me why the result is 9.199999809265137
instead of 9.2?

As far as i know floats should be less precise than double and indeed
java let me do implicit conversions from the former to the latter and
not the opposite. But when converting a small error is introduced even
if the converted number is easily represented with exact precision in
both formats.

I also noticed that this error is not introduced in the conversion
only when the float values are easily represented using a fixed point
notation, i.e. all integer values or values such as 9.5, 3.25, 2.75,
12.125 etc. I expect Java to use standard floating point mantissa and
exponent notation which produce precision in terms of meaningful
digits, which is different from fixed point notation typical
representation errors.

So, why is this error introduced when promoting a float value to a
higher precision double and why is this error introduced only in the
above cases?
 
S

Stefan Ram

Gabriele said:
public static void main(String[] args) {
double b = 9.2f;
System.out.println(b);
}
could someone explain to me why the result is 9.199999809265137
instead of 9.2?

This is not the result, but the output. Methods might have
results. Programs have behavior.

»9.199999809265137« is the
java.lang.String.valueOf-representation of the value
»( double )9.2f«. The value of the decimal numeral »9.2«
cannot be represented by the type »float«, so an approximation
was chosen. The string value of this approximation uses yet
another approximation, whose text representation is what
this program prints.
But when converting a small error is introduced even
if the converted number is easily represented with exact precision in
both formats.

It is not. (At least in the case »9.2« of the above programs.)

Try »9.25«, this should be »easily represented with exact
precision«.

Hint: Try to convert »9.2« to binary and post the precise
result here.
 
G

Gabriele

  9.199999809265137 is the
  java.lang.String.valueOf-representation of the value
  ( double )9.2f .

Fine to me. But that does not explain why the String.valueOf
representation of both the values 9.2f and 9.2d is exactly 9.2 while
this does not hold true for the promoted (double)9.2f
  It is not. (At least in the case 9.2 of the above programs.)

sign * mantissa * radix ^ exponent

Is the radix fixed to 2 in the machine representation?
If so, you are right, 9.2 is hard to encode exactly.

Still, why such approximation is manifest when converting from float
to double and does not occur when storing or when demoting the double?

All these variables are printed as the expected value without approx
errors:

double a = 9.2d;
float c = (float)9.2d;
float d = 9.2f;

It's especially not clear to me why approx errors occurs with promoted
floats and not with demoted double.
 
S

Stefan Ram

Gabriele said:
Fine to me. But that does not explain why the String.valueOf
representation of both the values 9.2f and 9.2d is exactly 9.2 while
this does not hold true for the promoted (double)9.2f

Let's look at the values:

public class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println( new java.math.BigDecimal( 9.2f ));
java.lang.System.out.println( new java.math.BigDecimal( 9.2d ));
java.lang.System.out.println( new java.math.BigDecimal(( double )9.2f )); }}

9.19999980926513671875
9.199999999999999289457264239899814128875732421875
9.19999980926513671875

Now let's look at the java.lang.String.valueOf-representations:

public class Main
{ public static void main( final java.lang.String[] args )
{ java.lang.System.out.println( java.lang.String.valueOf( 9.2f ));
java.lang.System.out.println( java.lang.String.valueOf( 9.2d ));
java.lang.System.out.println( java.lang.String.valueOf(( double )9.2f )); }}

9.2
9.2
9.199999809265137

I guess that java.lang.String.valueOf( double ) is optimized to
»beautify« typical double representations, such as
9.199999999999999289457264239899814128875732421875, while

java.lang.String.valueOf( float ) is optimized to
»beautify« typical float representations, such as
9.19999980926513671875.

In the last line, however, we call java.lang.String.valueOf( double )
with a typical float representation, so it cannot do its work
so beautifully as in the previous two cases.
Is the radix fixed to 2 in the machine representation?

For »double« and »float«: yes.
 
M

markspace

Is the radix fixed to 2 in the machine representation?


Of course.

It's especially not clear to me why approx errors occurs with promoted
floats and not with demoted double.


All of the examples you gave, I could see why they'd be rounded
correctly, although I probably couldn't explain in detail. Basically,
losing precision is easier to deal with. When you go from double to
float, then you can approximate and round correctly. When you go from
float to double, you'd have to invent extra digits that you don't have
-- that cannot be done.
 
J

Joshua Cranmer

As far as i know floats should be less precise than double and indeed
java let me do implicit conversions from the former to the latter and
not the opposite. But when converting a small error is introduced even
if the converted number is easily represented with exact precision in
both formats.

It's not expressible with exact precision (1/10 is a repeating decimal
in binary). The value of 9.2 in a float is:

s eeee eeee mmmm mmmm mmmm mmmm mmmm mmm
0 1000 0010 0010 0110 0110 0110 0110 011

Notice the repeating decimal digit. Upon conversion to double, the
number you then get is:

s eeee eeee eee mmmm mmmm mmmm mmmm mmmm mmmm mmmm mmmm...
0 1000 0000 010 0010 0110 0110 0110 0110 0110 0000 0000...

The number 9.2 in a double is:
0 1000 0000 010 0010 0110 0110 0110 0110 0110 0110 0110...

Note that the two numbers are not the same--that is not a 9.2 double.
So, why is this error introduced when promoting a float value to a
higher precision double and why is this error introduced only in the
above cases?

By default, Java treats all floating-point literals as doubles, not
floats. The suffix `f' makes the literal a float literal, which gets you
just 23 bit mantissa, insufficient when upcast to a 52 bit mantissa.

Note too that Java has magic in the Double.toString() and
Float.toString() methods which truncates the digit to just one decimal
place if it is the closest representation of said number. So
Float.toString(9.2f).equals(Double.toString(9.2)) will always return true.
 
G

Gabriele

Gabriele said:
Fine to me. But that does not explain why the String.valueOf
representation of both the values 9.2f and 9.2d is exactly 9.2 while
this does not hold true for the promoted (double)9.2f

  Let's look at the values:

public class Main
{ public static void main( final java.lang.String[] args )
  { java.lang.System.out.println( new java.math.BigDecimal( 9.2f ));
    java.lang.System.out.println( new java.math.BigDecimal( 9.2d ));
    java.lang.System.out.println( new java.math.BigDecimal(( double )9.2f )); }}

9.19999980926513671875
9.199999999999999289457264239899814128875732421875
9.19999980926513671875

  Now let's look at the java.lang.String.valueOf-representations:

public class Main
{ public static void main( final java.lang.String[] args )
  { java.lang.System.out.println( java.lang.String.valueOf( 9.2f ));
    java.lang.System.out.println( java.lang.String.valueOf( 9.2d ));
    java.lang.System.out.println( java.lang.String.valueOf(( double )9.2f )); }}

9.2
9.2
9.199999809265137

  I guess that java.lang.String.valueOf( double ) is optimized to
  beautify typical double representations, such as
  9.199999999999999289457264239899814128875732421875, while

  java.lang.String.valueOf( float ) is optimized to
  beautify typical float representations, such as
  9.19999980926513671875.

  In the last line, however, we call java.lang.String.valueOf( double )
  with a typical float representation, so it cannot do its work
  so beautifully as in the previous two cases.
Is the radix fixed to 2 in the machine representation?

  For double and float : yes.

Thanks. That was very clear.
 
M

markspace

Note too that Java has magic in the Double.toString() and
Float.toString() methods which truncates the digit to just one decimal
place if it is the closest representation of said number. So
Float.toString(9.2f).equals(Double.toString(9.2)) will always return true.


Just one digit? I did a quick test and I think it's somewhat more
sophisticated than that:

System.out.println( 9.22f );
System.out.println( 9.2222f );

Both print as expected, 9.22 and 9.2222 respectively.
 
J

Joshua Cranmer

Just one digit? I did a quick test and I think it's somewhat more
sophisticated than that:

At least one digit. There may be a cutoff, or perhaps the toString
method may try seeing if it's the closest representation for every
additional digit. All I know is that the actual source is thousands of
lines of code just to do the output, and that there is some amount of
magic involved.
 
A

Arne Vajhøj

Of course.

In all newer HW because they use IEEE 754 and in Java context
because Java mandates IEEE 754.

But other values has been used.

Rather old IBM Mainframes used 16.

Arne
 
L

Lew

Gabriele said:
Hi everybody. I have a question about floating point promotion.
Given the following code:

public static void main(String[] args) {
double b = 9.2f;
System.out.println(b);
}

could someone explain to me why the result is 9.199999809265137
instead of 9.2?

As far as i know floats should be less precise than double and indeed
java let me do implicit conversions from the former to the latter and
not the opposite. But when converting a small error is introduced even
if the converted number is easily represented with exact precision in
both formats.

I also noticed that this error is not introduced in the conversion
only when the float values are easily represented using a fixed point
notation, i.e. all integer values or values such as 9.5, 3.25, 2.75,
12.125 etc. I expect Java to use standard floating point mantissa and
exponent notation which produce precision in terms of meaningful
digits, which is different from fixed point notation typical
representation errors.

So, why is this error introduced when promoting a float value to a
higher precision double and why is this error introduced only in the
above cases?

Read and assimilate this article:
<http://docs.sun.com/source/806-3568/ncg_goldberg.html>
 
L

Lew

Sherm said:
Given the number of links to that, I wonder if Oracle will manage to
put a proper redirect in place for it...

It's not the canonical location anyway.

I find it shocking and very, very sad that people enter programming without
the faintest whiff of a hint of a clue about numerical analysis. Our
educational institutions are derelict in their duty.

No one should ever be allowed to collect a programming paycheck without at
least being aware that floating-point numbers are approximations of real
numbers and that that is related to why "9.2f" (or "d") is not precisely equal
to 9.2 (decimal), even if they don't know the particulars. It's a FAQ, for
God's sake! And the querents always seem so surprised!

Yeesh.
 
M

Martin Gregorie

In all newer HW because they use IEEE 754 and in Java context because
Java mandates IEEE 754.

But other values has been used.

Rather old IBM Mainframes used 16.
Presumably there is some sort of tie-in to the packed BCD numeric
representation which all current IBM mainframes (and most S/360s) support?
 
R

Roedy Green

could someone explain to me why the result is 9.199999809265137
instead of 9.2?

The short answer is 9.2 in a repeater in binary. Double and float are
kept in binary. Another short answer is there is no practical
difference between a tree 9.2 metes tall and one 9.199999809265137
meters tall. Floating point is for measurements.

See http://mindprod.com/jgloss/floatingpoint.html
for a more detailed answer.
 
A

Arne Vajhøj

I find it shocking and very, very sad that people enter programming
without the faintest whiff of a hint of a clue about numerical analysis.
Our educational institutions are derelict in their duty.

No one should ever be allowed to collect a programming paycheck without
at least being aware that floating-point numbers are approximations of
real numbers and that that is related to why "9.2f" (or "d") is not
precisely equal to 9.2 (decimal), even if they don't know the
particulars. It's a FAQ, for God's sake! And the querents always seem so
surprised!

A lot of developers never had any reason to use FP.

Of course not learning about FP occasionally make them
think they should use them where they should not.

But if we say that we get 300000-400000 new developers
every year, then there will always be some that have
not learned about FP and when not to use them.

Arne
 
L

Lew

A lot of developers never had any reason to use FP.

Of course not learning about FP occasionally make them
think they should use them where they should not.

But if we say that we get 300000-400000 new developers
every year, then there will always be some that have
not learned about FP and when not to use them.

And those ignoramuses have no right to a paycheck when developers who actually
know something about programming are out there.

I'm not even setting the bar as high as "have ... learned about FP", only that
they at least have noticed that floating point is not the same as real
numbers. What kind of respect can you have for programming as a profession,
Arne, if you are willing to tolerate such an egregious level of ignorance and
dereliction as to permit less?

I say it's better to hold professionals to a professional standard than to
make excuses for the incompetent. I suggest you read the short store
"Harrison Bergeron" by Kurt Vonnegut, Jr., for a chilling picture of the evil
that such pseudo-egalitarianism as you expressed above can engender.
 
A

Arne Vajhøj

And those ignoramuses have no right to a paycheck when developers who
actually know something about programming are out there.

I'm not even setting the bar as high as "have ... learned about FP",
only that they at least have noticed that floating point is not the same
as real numbers. What kind of respect can you have for programming as a
profession, Arne, if you are willing to tolerate such an egregious level
of ignorance and dereliction as to permit less?

I say it's better to hold professionals to a professional standard than
to make excuses for the incompetent. I suggest you read the short store
"Harrison Bergeron" by Kurt Vonnegut, Jr., for a chilling picture of the
evil that such pseudo-egalitarianism as you expressed above can engender.

I think it would be great if all developers knew about FP.

I also think it would be great if there were no hunger, war or
crimes in this world.

But it is not going to happen.

With 300000-400000 new developers every year there will be
a huge number of new developers that does not know about FP.

It is fine to educate them. But there is no reason to be
surprised.

It is not really egalitarianism. It is realism.

There are not much point in being puzzled by the
fact that the world is how it is not as it should be.

Arne
 
L

Lew

I think it would be great if all developers knew about FP.

Again, I'm only saying that anyone who takes an introductory course in
programming should at least be exposed to the notion that floating-point
numbers are an approximation to real numbers. I am not claiming that all
programmers should have mastered every aspect of numerical analysis.
I also think it would be great if there were no hunger, war or
crimes in this world.

Ooo, snap!

That is so not relevant.
But it is not going to happen.

With 300000-400000 new developers every year there will be
a huge number of new developers that does not know about FP.

So they've never taken a programming course?

Come on! Programming is a skilled profession. You need training to do it.
All I am claiming is that that training ought to include the actual principles
of computer programming. You apparently don't feel that it's necessary that
programmers be trained in the art.
It is fine to educate them. But there is no reason to be
surprised.

It is not really egalitarianism. It is realism.

That's like saying doctors shouldn't be trained in medicine, or accountants in
double-entry bookkeeping. There is a minimum body of knowledge required in
any profession, and that preparation is supposed to enable a practitioner to
handle, or to learn how to handle the variety of tasks they may encounter.
For programmers, that education should include the notion that floating-point
is an approximation. Anything less is below the minimum to be a professional
programmer.

Airline pilots don't usually have to crash land, but they darn well better
know something of what it requires if they do, as Capt. Sullenberger can
attest. There are just certain things one has to know in a profession.
There are not much point in being puzzled by the
fact that the world is how it is not as it should be.

So you are supporting the notion that a person can go four years to college
and take even an introductory programming course that never, ever mentions
that floating point is not the same as real numbers? You justify inaction and
lax standards with the notion that "that is how the world is", and feel that
we should take no action to improve it? We should not expect programming
courses to teach programming? We should go ahead and hire programmers who do
not know even the simplest, most basic information about programming? Really?
You are that resigned and unwilling to stand on even the most elementary of
principles?

No wonder the state of the art is degrading as it is, if this attitude is so
widespread.

And comparing the notion that professionals should be required to have
knowledge of their profession to world hunger is a fallacious argument. Nice
rhetoric, but not evidentiary or germane to the argument.

I do not want to live in the world where our professionals are not required to
know the basics of their profession. Here and now I take the stand that
programmers should know how to program. Perhaps the notion that that is not
necessary is a factor in all the crappy code out there.
 

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
474,044
Messages
2,570,388
Members
47,052
Latest member
ketan

Latest Threads

Top