Tuesday, April 15, 2008

Arrrggghhhh .....

Arrghhh!!! Try this:

Transcript show: (50.0 - 7.23) asString

returns 42.77


int main(int argc, char ** argv) {
double a = 50.0 - 7.23;
printf("%lf", a);

returns 42.770000

public class Test {
public static void main(String[] args) {
double a = 50.0 - 7.23;

returns 42.769999999999996


Randal L. Schwartz said...

You don't even need the #asString. Transcript>>#show: does that automatically. At least, it does in Squeak.

Andrés said...

Note that the calculation stated will not be carried out with the precision implied by seeing the numbers written in base 10 notation. Is this perhaps an issue of dissimilar printing policies?

Robert said...

Take time an read of http://docs.sun.com/source/806-3568/ncg_goldberg.html

Your example is just showing floating point arithmetic problems (feature), and by coincidence the C/C++ example did not showed that behavior, at least the Java example behave the same on every platform and does not depends on the C compiler and C runtime used

I know the Smalltalk way looks more polished, but I like the Java way to use Decimal arithmetic only when I need them (decimal arithmetic is slower). I only hope Java had a way to use BigDecimal instances with simple operator syntax instead of methods, look at the way new EcmaScript 4 will treat decimals, that is elegant in my opinion


By the way I am a Smalltalk developer (learned Object Orientation with it) so this is not anything against Smalltalk. only that I had many times the need to move code that requires high performance to native code (Smalltalk primitives) because the use of pure Decimal objects, at least at that time with VisualAge Smalltalk

nicolas cellier said...

Remember this: Float are special kind of fraction with denominator being an exact power of 2 and numerator limited to 53 bits in double precision...
And thus Float will do inexact operations except in a limited number of cases...

So all you see is the rounding of this fraction to a certain number of digits in base 10.
There is no contradiction there.
I bet java did put enough digits by default such that the number can be re-interpreted unchanged.

You might want to test this:
50 - 7.23 = 42.77
In squeak 3.10 were correct parsing of Float is implemented, the answer is false, and:
50 - 7.23 = 42.769999999999996 -> true.

Unfortunately, unlike recent versions of Squeak, most Smalltalk don't interpret decimal floating point representation accurately. They fail to answer the nearest Floating point number due to cumulated round off errors caused by naive algorithm.

Duncan said...

After reading this post, I tried running the same code on my Scheme system, and I got the same result as Java:

> (- 50.0 7.23)

Later on, I found out that there's a way to get the 'right' answer:

> (exact->inexact (- #e50.0 #e7.23))

Also, starting with Java 1.5, you can use

System.out.printf (String format, Object... args)

John Dougan said...

Have you tried looking at the actual bytes of all the floats to see if they're REALLY the same, as opposed to just printing the same?

greedycat said...

In java note that running the following will give: 42.77
float a = 50.0F - 7.23F;

cdrick said...

0.1 asFraction -> (3602879701896397/36028797018963968)
0.1 asApproximateFraction -> (1/10)

I discover the float problem recently, and so I discovered scaled decimals:
0.1s1 asFraction -> (1/10)

My test was in squeak (3.9, 3.10)...
1 - 0.1 -0.1 -0.1 = 0.7 -> false

Torsten said...

The aarghhh effect was caused by the different output I got:

My program was comparing calculations
and I had a LONG search in logs to find out that Java printed it like that. I expected it to print it as 42.77 as I knew from other languages/tools.