Smalltalk
Transcript show: (50.0 - 7.23) asString
returns 42.77
C/C++
#include
int main(int argc, char ** argv) {
double a = 50.0 - 7.23;
printf("%lf", a);
}
returns 42.770000
Java
public class Test {
public static void main(String[] args) {
double a = 50.0 - 7.23;
System.out.println(a);
}
}
returns 42.769999999999996
You don't even need the #asString. Transcript>>#show: does that automatically. At least, it does in Squeak.
ReplyDeleteNote 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?
ReplyDeleteTake time an read of http://docs.sun.com/source/806-3568/ncg_goldberg.html
ReplyDeleteYour 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
http://dev.opera.com/articles/view/why-i-love-ecmascript-4-real-decimals/
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
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...
ReplyDeleteAnd 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.
After reading this post, I tried running the same code on my Scheme system, and I got the same result as Java:
ReplyDelete> (- 50.0 7.23)
42.769999999999996
Later on, I found out that there's a way to get the 'right' answer:
> (exact->inexact (- #e50.0 #e7.23))
42.77
Also, starting with Java 1.5, you can use
System.out.printf (String format, Object... args)
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?
ReplyDeleteIn java note that running the following will give: 42.77
ReplyDeletefloat a = 50.0F - 7.23F;
0.1 asFraction -> (3602879701896397/36028797018963968)
ReplyDelete0.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
The aarghhh effect was caused by the different output I got:
ReplyDeleteMy 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.