File APIs for Java Developers
Manipulate DOC, XLS, PPT, PDF and many others from your application.
http://aspose.com/file-tools
The moose likes Java in General and the fly likes Strange fractions! Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login


Win a copy of Murach's Java Servlets and JSP this week in the Servlets forum!
JavaRanch » Java Forums » Java » Java in General
Bookmark "Strange fractions!" Watch "Strange fractions!" New topic
Author

Strange fractions!

Tony Walters
Ranch Hand

Joined: Feb 13, 2003
Posts: 54
Hi all

I was playing with some primitive casting, like so:

public class Test {

public static void main(String[] args) {

float f = (float)99.9;
double d1 = 99.9;
double d2 = f;
System.out.println("f: " + f);
System.out.println("d1: " + d1);
System.out.println("d2: " + d2);
}
}

Here's the output:

99.9
f: 99.9
d1: 99.9
d2: 99.9000015258789

I'd be *very* grateful if someone could explain to me why d2 seems to be greater than d1 (I know its not much, but don't understand why!).

Ta

Tony
M Beck
Ranch Hand

Joined: Jan 14, 2005
Posts: 323
you might want to read this paper.

in short, floating-point types like "float" and "double" are never exact; they are only approximations of the number you want. the differences between the number you want and the number you get, with these types, are complex and detailed, but can be considered more or less random, at least as a rule of thumb.

moreover, the differently-sized floating point types (float versus double, in your case) are inexact in different ways. "double" has more power to represent more decimal places — or to represent larger numbers without dropping low-order digits — but there's not necessarily any one-to-one correspondence between the numbers a "float" can represent and those that "double" can represent, and the inaccuracies each format will introduce are different too.

this is just a fact of life when using floating-point numbers. if it's simply not acceptable, either use rounding methods to your desired number of decimal points, or find a way to make do with integers alone.
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
Originally posted by M Beck:
in short, floating-point types like "float" and "double" are never exact; they are only approximations of the number you want.


Well, that's not *totally* true - 0.5 for example can always be presented exactly, as well as 0.25, 0.75 ...

The point is that float and double use the binary system, whereas your literals are written in the decimal system. Not all finite decimal numbers translate to finite binary numbers, though. 0.1, for example, becomes an infinite number in the binary system! Because both float and double have to stop somewhere, but double uses higher precision, a 0.1d is a little bit bigger than a 0.1f...

As a similar example, consider how the ternary number 0.1 (= 3^-1 = 1/3) becomes an infinite number when translated to the decimal system.


The soul is dyed the color of its thoughts. Think only on those things that are in line with your principles and can bear the light of day. The content of your character is your choice. Day by day, what you do is who you become. Your integrity is your destiny - it is the light that guides your way. - Heraclitus
M Beck
Ranch Hand

Joined: Jan 14, 2005
Posts: 323
very true. but more to the original poster's point, even though double has higher precision than float, it's not necessarily a superset of float — there may be (and probably are) many numbers that "float" can represent exactly yet double can only approximate.

to make a long story short, the problem mr. Walters was seeing stems from a floating-point conversion operation. when a float is cast to a double, the implicit conversion — like any other operation on floating-point numbers, really — always runs a risk of rounding error, introducing inaccuracy. frankly, i'm surprised that a double declared from a constant doesn't also reduce to the same inaccurate approximation as the double cast from a float. i can only assume that the compiler uses a different conversion method when reading constants from source code than the JVM uses when casting variables at run-time. which is odd, but i've seen odder...
Jeroen Wenting
Ranch Hand

Joined: Oct 12, 2000
Posts: 5093
Originally posted by Ilja Preuss:


Well, that's not *totally* true - 0.5 for example can always be presented exactly, as well as 0.25, 0.75 ...


Mathematically it's indeed not totally true, but in the context of computer floating point mathematics in computers using a discrete system of representing data it is


42
Tony Walters
Ranch Hand

Joined: Feb 13, 2003
Posts: 54
Thanks guys. That one really stumped me. I've been using Java (a lot) for 5 years or so, but never come across that. Simple when explained really.

Ta

Tony
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
Originally posted by Jeroen Wenting:
Mathematically it's indeed not totally true, but in the context of computer floating point mathematics in computers using a discrete system of representing data it is


Sorry, I don't understand this. Are you saying that there are no values that can be represented exactly by IEEE floating point numbers? That sounds obviously wrong to me...
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
Originally posted by M Beck:
i'm surprised that a double declared from a constant doesn't also reduce to the same inaccurate approximation as the double cast from a float.


As far as I know, it does. It's just that Java "knows" that the internal representation is inaccurate, and therefore manages to conceal it to some amount when printing to the console.

Try the following code:

Jeroen Wenting
Ranch Hand

Joined: Oct 12, 2000
Posts: 5093
There are no floating point numbers that can be guaranteed to be represented without rounding errors.
A binary system doesn't care whether something is a "nice" fracture after all. 2463/4235327 is a nice fracture yet I doubt 0.0010936581756261086806284378986558 (which was calculated using a PC based calculator) can be guaranteed to be without rounding errors.

1/2 will usually (probably in 99.999999999% of cases) deliver 0.5000000000000000 but in that last case it may produce 0.49999999999999994 instead. Now if the viewer wanted to see that result to a higher precision than that he'd get an unexpected result.
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
Originally posted by Jeroen Wenting:
There are no floating point numbers that can be guaranteed to be represented without rounding errors.


Of course there are. A float is just a number of bits that represent a number, and all numbers that can be represented using those bits are, of course, represented without "rounding errors". Wether those numbers can be represented in the decimal system using a finite representation is a different question - and that can certainly be answered with "yes" for some of the possible values.

A binary system doesn't care whether something is a "nice" fracture after all.


I didn't say that it does.

2463/4235327 is a nice fracture yet I doubt 0.0010936581756261086806284378986558 (which was calculated using a PC based calculator) can be guaranteed to be without rounding errors.


Which doesn't prove at all that there are *no* numbers at all that can be guaranteed to be without rounding errors.

1/2 will usually (probably in 99.999999999% of cases) deliver 0.5000000000000000 but in that last case it may produce 0.49999999999999994 instead.


1/2 is 0.1 binary. I'd think that there is a float bit pattern that *exactly* represents this value. And I'd assume that Java deterministically uses that exact value for literal values of 0.5f.

Of course that doesn't mean that *every computation* that theoretically should result in 1/2 ends up with that exact bit pattern. Is that what you were referring to?
 
 
subject: Strange fractions!
 
Similar Threads
Issue adding double value
wrapper class doubt
Dan's question
Double / Float Doubt.
double & float related Qn