Beefy Boxes and Bandwidth Generously Provided by pair Networks
XP is just a number
 
PerlMonks  

Re: Okay! What!?!?!?

by davido (Cardinal)
on Apr 23, 2014 at 06:26 UTC ( [id://1083281]=note: print w/replies, xml ) Need Help??


in reply to Okay! What!?!?!?

On my system (Perl5.18.2):

#!/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)


Dave

Replies are listed 'Best First'.
Re^2: Okay! What!?!?!?
by tobyink (Canon) on Apr 23, 2014 at 11:27 UTC

    It's been about 15 years since I've written any Pascal, but here you go...

    program floating; var A, B :real; begin A := 14.4e0; B := 10.0e0 + 14.4e0 - 10.0e0; writeln( A ); writeln( B ); if A = B then writeln('they are equal') else writeln('they differ'); end.

    Compiled using Free Pascal Compiler 2.6.2-5 (i386), I get the following output:

    1.44000000000000E+001 1.44000000000000E+001 they are equal

    I don't know if FPC is especially smart at optimizing the mathematical expressions, or especially smart at DWIM output and comparisons on floating point numbers. But it's being smart somehow.

    use Moops; class Cow :rw { has name => (default => 'Ermintrude') }; say Cow->new->name

      This could be explained by the compiler knowing to perform the constant folding in an order that reduces the risk of loss of precision.

      So do the addition and subtraction as separate steps.

      - tye        

      There must be some behind the scenes DWIMery, because according to the documentation, FreePascal's "real" type maps directly to a standard IEEE 754 "double" on most architectures, and as such, should suffer from the same shortcomings of representing floating point numbers in base 2.


      Dave

Re^2: Okay! What!?!?!?
by trizen (Hermit) on Apr 23, 2014 at 14:45 UTC

    Go suffers from this problem too. It uses an arbitrary number representation for constants only, which are computed at compile-time.

    For example, the following code:

    package main import "fmt" func main() { x := 14.4; y := 10.0; fmt.Printf("%.49f\n", x) fmt.Printf("%.49f\n", x+y-y) }
    Outputs:
    14.4000000000000003552713678800500929355621337890625 14.3999999999999985789145284797996282577514648437500

Re^2: Okay! What!?!?!?
by karlgoethebier (Abbot) on May 01, 2014 at 14:36 UTC
    "I just don't know any Java"

    Me too (not really). So a i used a GUI:

    Update: fixed typo.

    package Perlmonks; public class Testomato { public static void main(String[] args) { System.out.printf("%.49f\n",14.4); System.out.printf("%.49f\n", 10+14.4-10); } }

    I get:

    14,4000000000000000000000000000000000000000000000000 14,3999999999999990000000000000000000000000000000000

    Regards, Karl

    «The Crux of the Biscuit is the Apostrophe»

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://1083281]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others browsing the Monastery: (4)
As of 2024-04-23 22:19 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found