Win a copy of Spring Boot in Practice this week in the Spring forum!
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
• Campbell Ritchie
• Tim Cooke
• Ron McLeod
• Jeanne Boyarsky
• Paul Clapham
Sheriffs:
• Liutauras Vilda
• Henry Wong
• Devaka Cooray
Saloon Keepers:
• Tim Moores
• Stephan van Hulst
• Tim Holloway
• Al Hobbs
• Carey Brown
Bartenders:
• Piet Souris
• Mikalai Zaikin
• Himai Minh

# Strange fractions!

Ranch Hand
Posts: 54
• • Number of slices to send:
Optional 'thank-you' note:
• • 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

Ranch Hand
Posts: 323
• • Number of slices to send:
Optional 'thank-you' note:
• • 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.

author Posts: 14112
• • Number of slices to send:
Optional 'thank-you' note:
• • 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.

M Beck
Ranch Hand
Posts: 323
• • Number of slices to send:
Optional 'thank-you' note:
• • 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...

Ranch Hand
Posts: 5093
• • Number of slices to send:
Optional 'thank-you' note:
• • 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 Tony Walters
Ranch Hand
Posts: 54
• • Number of slices to send:
Optional 'thank-you' note:
• • 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 Posts: 14112
• • Number of slices to send:
Optional 'thank-you' note:
• • 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 Posts: 14112
• • Number of slices to send:
Optional 'thank-you' note:
• • 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
Posts: 5093
• • Number of slices to send:
Optional 'thank-you' note:
• • 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 Posts: 14112
• • Number of slices to send:
Optional 'thank-you' note:
• • 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? With a little knowledge, a cast iron skillet is non-stick and lasts a lifetime.