9999999999999999.0 - 9999999999999998.0Does your favorite language give the right answer?
Ruby: | irb(main):001:0> 9999999999999999.0 - 9999999999999998.0 2.0 |
---|---|
Java: | public class Foo{public static void main(String args[]){System.out.println(9999999999999999.0-9999999999999998.0);}} 2.0 |
Python: | >>> 9999999999999999.0 - 9999999999999998.0 2.0 |
Rebol: | >> 9999999999999999.0 - 9999999999999998.0 == 2.0 |
Haskell: | Prelude> 9999999999999999.0 - 9999999999999998.0 2.0 |
TCL: | % expr "9999999999999999.0-9999999999999998.0" 0.0 |
Emacs Lisp: | ELISP> (- 9999999999999999.0 9999999999999998.0) 2.0 |
Common–Lisp: | [1]> (- 9999999999999999.0 9999999999999998.0) 0.0 |
Maxima: | (%i1) 9999999999999999.0-9999999999999998.0; (%o1) 2.0 |
Google: | 0 |
K/Q: | q)9999999999999999.0-9999999999999998.0 2f |
JavaScript: | > 9999999999999999.0-9999999999999998.0 2 |
R: | > 9999999999999999.0-9999999999999998.0 [1] 2 |
Erlang: | 1> 9999999999999999.0-9999999999999998.0 . 2.0 |
C: | main(){printf("%lf\n",(double)9999999999999999.0-9999999999999998.0);} 2.000000 |
AWK: | $ awk 'END{print 9999999999999999.0-9999999999999998.0}'</dev/null 2 |
GoLang: | var a = 9999999999999999.0; var b = 9999999999999998.0; fmt.Printf("%f\n", a-b) 2.000000 |
Perl: | $ perl -e 'print 9999999999999999.0-9999999999999998.0;print "\n";' 2.0 |
Perl6: | $ perl6 -e 'print 9999999999999999.0-9999999999999998.0;print "\n";' 1 |
Wolfram: | 1 |
soup: | 9999999999999999.0-9999999999999998.0 1 |
Several of the results surprised me. Did they surprise you?
Note that some of the wrong answers can be fixed with various workarounds. For example Common–Lisp gives the correct answer for:
(let ((*read-default-float-format* 'long-float)) (- (read-from-string "9999999999999999.0") (read-from-string "9999999999999998.0")))and Perl will give the correct answer for:
perl -mMath::BigFloat -e 'print Math::BigFloat->new("9999999999999999.0") - Math::BigFloat->new("9999999999999998.0");print "\n";'
Using one of these workarounds requires a certain prescience of the data domain, so they were not generally considered for the table above.
I know that GoLang will produce the correct answer for
fmt.Printf("%f\n", 9999999999999999.0-9999999999999998.0)but not if the values are read. That Go uses arbitrary-precision for constant expressions seems dangerous to me.
JavaScript and others often have something like Number.MAX_SAFE_INTEGER but tooling rarely warns it is creating an unsafe integer.
Julien Palard wrote to tell me about "... https://0.30000000000000004.com/ to continue the surprises, also there's some nice explanations there. I like to write the URL like this in Python: f"https://{.1+.2}.com" it's shorter to type than the real one :D" which i thought was cute, and I think anyone who wants to understand more about floats will probably like that page too, but I would also like language designers to consider generating an error if they can't round-trip from the source code instead of giving confusing answers.
If I didn't include your favorite language, or if you think I misrepresented the canonical way to subtract two numbers in your favorite language, please let me know: geocar@sdf.org