#!/usr/bin/env perl
printf "%.49f\n", 14.4;
printf "%.49f\n", 10 + 14.4 - 10;
...outputs...
14.4000000000000003552713678800500929355621337890625
14.3999999999999985789145284797996282577514648437500
And (GNU C++).....
#include <iostream>
#include <iomanip>
using namespace std;
int main () {
cout << setprecision(51) << endl;
cout << 14.4 << endl;
cout << 10 + 14.4 - 10 << endl;
return 0;
}
...outputs...
14.4000000000000003552713678800500929355621337890625
14.39999999999999857891452847979962825775146484375
And (GNU C)
#include <stdio.h>
int main (void) {
printf("%.49f\n", 14.4);
printf("%.49f\n", 10.0 + 14.4 - 10.0);
return 0;
}
...produces this output:
14.4000000000000003552713678800500929355621337890625
14.3999999999999985789145284797996282577514648437500
This is because the decimal value 14.4 cannot be perfectly represented as a fraction in the form of n/(2^m), and therefore has a non-terminating binary expansion.
The code I've shown above is first Perl, and second C++, and the third, C, just to illustrate that this is not a problem specific to just Perl. Here's yet another link that attempts to explain it: Re: shocking imprecision
Update: Here's a Lisp (Racket, a Scheme derivative) example as well:
#!/usr/bin/env racket
#lang racket
(displayln (~a 14.4 #:width 15 #:pad-string "0"))
(displayln (~a (- (+ 10 14.4) 10) #:width 15 #:pad-string "0"))
(= 14.4 (- (+ 10 14.4) 10))
...outputs...
14.400000000000
14.399999999999
#f
(The "#f" means "false"; 14.40 doesn't equal 14.399...)
JavaScript (minimal example):
alert(10+14.4-10);
The pop-up displays: "14.399999999999999"
Python:
>>> print "%.49f"%14.4
14.4000000000000003552713678800500929355621337890625
>>> print "%.49f"%(10+14.4-10)
14.3999999999999985789145284797996282577514648437500
Ruby:
$ ruby -e 'printf "%.49f\n%.49f\n",14.4, 10+14.4-10'
14.4000000000000003552713678800500929355621337890625
14.3999999999999985789145284797996282577514648437500
SQL (sqlite):
sqlite> select 14.4 - (10 + 14.4 - 10);
1.77635683940025e-15
Couldn't remember enough Pascal. "Go" must optimize away the math, because while it does produce an imprecise representation of 14.4, it produces the same imprecise representation for both 14.4, and 10+14.4-10. (GO):
package main
import "fmt"
func main() {
fmt.Printf("%.49f\n",14.4)
fmt.Printf("%.49f\n", 10+14.4-10)
}
---------
14.4000000000000003552713678800500929355621337890625
14.4000000000000003552713678800500929355621337890625
Program exited.
Update: I left out Java because node lengths at PerlMonks are restricted to 64k (j/k -- I just don't know any Java)
|