32 ms·
0.30000000000000004
- ThePhysicist 11y agoI just have to post this: http://www.smbc-comics.com/?id=2999 http://www.smbc-comics.com/?id=2999 So it seems SQL does not give access to the secret robot Internet...
- scrollaway 11y agoI think this sort of captcha could actually work, hah.
- JupiterMoon 11y agoFor a short while but I'm sure that bot makers would use a decimal library if this became common.
- teddyh 11y agoThis table does not show which languages have support for Decimal numbers, which does the calculation exactly.
- dagw 11y agoBasically all languages have a Decimal number library you can use if you need it.
- protonfish 11y agoCan it calculate 1/3 exactly? You can in trinary: It's 0.1. Binary, decimal, trinary, or any other numbering system is no more accurate or "exact" than any other. They all have fractions that they cannot represent.
- recursive 11y agoFor that you'd need a Rational.
- mehrdada 11y ago"Computers can only natively store integers, so they need some way of representing decimal numbers" Technically, [digital] computers only natively "store" high and low voltages. The interpretation of a sequence of those signals as "integers" is entirely up to you. In all seriousness, representing integers is not a given either (e.g. two's complement vs one's complement, BCD, bignum, sparse integers, etc.). If you are going down in abstraction levels to describe floating point representation, you should not just call integers "native" blindly. Furthermore, floating point is not the only way to represent computation involving real values. It is indeed possible to represent computation on real values symbolically in many cases and lazily compute arbitrary precision results for output-printing purposes.
- illumen 11y agoTechnically, much storage does not need voltage being high or low either. Pits burned with lasers, and magnetic changes are also common ways to store stuff that don't involve voltage in the stored state. Here you can see python has a fractions.Fraction type which can be used for rational number arithmetic. >>> from fractions import Fraction >>> Fraction("0.1") + Fraction("0.2") Fraction(3, 10) >>> repr(float(Fraction("0.1") + Fraction("0.2"))) '0.3' Here we see the floating point behaviour. >>> 0.1 + 0.2 0.30000000000000004 Here we see that python has a nice behaviour for when printing floats. >>> print(0.1 + 0.2) 0.3 Here is a common error where people feed the input of Fraction (and Decimal) with a float. Even though you use the Fraction here it still carries the floating point error through. >>> Fraction(0.1) + Fraction(0.2) Fraction(10808639105689191, 36028797018963968) >>> float(Fraction(0.1) + Fraction(0.2)) 0.30000000000000004 Here is the Decimal type which does not have this float problem. Some people have argued (including myself) that Decimal should be used by python instead of float. Since this is much friendlier to people doing things like adding these numbers together. >>> from decimal import Decimal >>> Decimal("0.1") + Decimal("0.2") Decimal('0.3') >>> float(Decimal("0.1") + Decimal("0.2")) 0.3
- jessaustin 11y agoHere is the Decimal type which does not have this float problem. Are you sure? >>> Decimal(0.1) Decimal('0.1000000000000000055511151231257827021181583404541015625')
- kozak 11y agoLet's start another round of DEC64 discussion? ;-) http://www.dec64.com/ http://www.dec64.com/
- jrapdx3 11y agoFWIW, tried this with two less common languages: Tcl: + 0.1 0.2 0.30000000000000004 Chicken Scheme: (+ 0.1 0.2) 0.3 Same results under Windows 8.1 and FreeBSD 10.2. I suppose one is as "right" as the other, at least both answers equally popular among languages.
- pdkl95 11y agoAnother less-common language. The docs suggests they use "C doubles" for all floats. Welcome to SWI-Prolog (Multi-threaded, 64 bits, Version 6.6.6) ?- Sum is 0.1 + 0.2. Sum = 0.30000000000000004.
- dTal 11y agoAlso Chicken Scheme: (- 0.3 (+ 0.1 0.2)) -5.55111512312578e-17 Of course you can always (use numbers), but then you have to use (/ 1 20) and (/ 2 10). "0.3" is still considered "inexact", because of the decimal point. I don't like this - finite decimals are perfectly rational numbers and trivially convertible, why can't the interpreter treat them as such?
- jdaley 11y agoWhat are the differences in implementation of the languages that cause some to show a rounding error and others not?
- morsch 11y agoI suspect in many instances it's down to the method doing the printing being "helpful". The page documents this behaviour with Python. I've never specifically used C#, but it seems to default to the "G" format[1], the alternative "R" format shows the expected result. You can play around with it here: http://ideone.com/hxD96J http://ideone.com/hxD96J Printing out is kind of a misleading check here, maybe a better idea would be to test equality with the constant 0.3. Of course the site is just a neat illustration and not a technical whitepaper. [1] https://msdn.microsoft.com/en-us/library/dwhawy9k(v=vs.110).aspx https://msdn.microsoft.com/en-us/library/dwhawy9k(v=vs.110).... and https://msdn.microsoft.com/en-us/library/3hfd35ad(v=vs.110).aspx https://msdn.microsoft.com/en-us/library/3hfd35ad(v=vs.110)....
- yellowstuff 11y agoYes, I agree this page is misleading. It makes it look like C# is using rational numbers instead of floating point. In fact the "G" format defaults to 15 digits of precision for doubles, which is few enough to avoid ugly strings in many simple situations, but not all: > Console.WriteLine((.1 + .2)-.3); > Result: 5.55111512312578E-17
- langarto 11y agoThe printing routine. Internally, none of them can store 0.3 in a floating point variable because it is impossible to do so in exponential notation with base 2 (which is what IEE 754 uses). Some languages may optionally use an exact representation (e.g., Scheme or Python), but that's not the general case.
- annnnd 11y agoWhat Every Computer Scientist Should Know About Floating-Point Arithmetic: https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html https://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.h...
- tbronchain 11y agoHere is the part that made me understand it all: "Floating-point representations have a base (which is always assumed to be even) and a precision p. If = 10 and p = 3, then the number 0.1 is represented as 1.00 × 10-1. If = 2 and p = 24, then the decimal number 0.1 cannot be represented exactly, but is approximately 1.10011001100110011001101 × 2-4."
- teh 11y agoPython's print method is actually fairly clever picking the "nicest" representation that's still correct. https://docs.python.org/2/tutorial/floatingpoint.html#tut-fp-issues https://docs.python.org/2/tutorial/floatingpoint.html#tut-fp... Quote: "In current versions, Python displays a value based on the shortest decimal fraction that rounds correctly back to the true binary value, resulting simply in ‘0.1’."
- mkesper 11y agoAdditionally, for exact calculations you might want to use the decimal module. https://docs.python.org/3.5/library/decimal.html#module-decimal https://docs.python.org/3.5/library/decimal.html#module-deci...
- Spidler 11y agoBut be wary so you don't pass in floats when creating your decimals In [10]: from decimal import Decimal In [11]: Decimal(0.1) + Decimal(0.2) - Decimal(0.3) Out[11]: Decimal('2.775557561565156540423631668E-17') In [12]: Decimal("0.1") + Decimal("0.2") - Decimal("0.3") Out[12]: Decimal('0.0')
- fulafel 11y agoTry the usual decimally-unrepresentable numbers (like 1/3).
- mkesper 11y agoAs illumen pointed out, Python has also got fractions. For things like Pi however, there is no exact numerical representation and you'd probably want sympy or something similar.
- fulafel 11y agoSure. But the inability to represent 1/3 in decimal is just the same as inability to represent 1/10 in binary. The binary case just seems different because we are using a foreign base (decimal) literal "0.1" to express the binary number.
- avian 11y agoI'm not sure what was the intended message of the table of examples. It is possible in many languages to get both types of ASCII representations for floating point: a nice human-readable 0.3 and the technically correct 0.30000000000000004. But some examples seem artificially biased towards one or the other. Only for Python both variants are shown. And then some examples use decimal representations, which are not floating point at all. For instance, in Perl "print 0.1+0.2" will give you "0.3" just like in Python, while the printf format shown here will give you the non-rounded representation. And there are of-course decimal and rational number packages for Perl as well.
- Tepix 11y agoYep, it's better to print the result of 0.1+0.2-0.3
- bmn_ 11y agoNot generally! $ perl -E 'say sprintf "%.64f", 0.1 + 0.2' 0.3000000000000000000108420217248550443400745280086994171142578125 $ perl -E 'say sprintf "%.64f", 0.1 + 0.2 - 0.3' 0.0000000000000000000000000000000000000000000000000000000000000000 My Perl is configured with -Dusemorebits. https://metacpan.org/pod/distribution/perl/INSTALL#more-bits https://metacpan.org/pod/distribution/perl/INSTALL#more-bits
- panic 11y agoThis is more a comparison of output routines than anything else. In PHP, one of the languages that gives the "correct" result: php > echo .1 + .2; 0.3 php > if (.1 + .2 === .3) { echo "equal"; } else { echo "not equal"; } not equal
- nolok 11y agoErrr that's exactly what the page implies; it does not say nor imply "those that display .3 are doing it correctly internaly". One of the cardinal rule of floating point in computing is that you never do direct comparison between values, whatever the language, so your test should never ever be used. That doesn't mean a language cannot be allowed to infer what the correct display of a floating point value should be.
- deleted 11y ago[deleted]
- Tepix 11y agoJust adding 0.1 to 0.2 in the language of your choice can be misleading because printing the number might just cut off the digits at some point. Here's an example using perl5: perl -e 'print 0.1+0.2' yields '0.3', which looks OK, however perl -e 'print 0.1+0.2-0.3' reveals '5.55111512312578e-17' So, it's better to print the result of 0.1+0.2-0.3 For what its worth, perl6 passes this test with flying colours.
- static_noise 11y ago> For what its worth, perl6 passes this test with flying colours. Do we really expect calculations on floating point numbers to be the same as calcualtions with real numbers? The only problem I see is that often the floating point format is not specified properly. When one writes "0.3", what does it actually mean? Does the format the compiler uses internally conform to IEEE 754? Is it 32bit, 64bit, 80bit or something else?
- Piskvorrr 11y agoIn other words, there are about 5648798746465 possible interpretations of the "(\+|-|)[0-9]+.[0-9]+" format, and the problem is with mismatched assumptions ("of course I'm using the One Correct Interpretation, like everyone else!").
- panic 11y agoThe only problem I see is that often the floating point format is not specified properly. When one writes "0.3", what does it actually mean? It's perfectly well-specified. If you are using double-precision floating point, "0.3" means 0x3fd3333333333333 (as bits), or 0.299999999999999988897769753748434595763683319091796875 (as an exact number: the closest representable number to 0.3).
- static_noise 11y agoWhen your compiler does its internal calculations in double precision float you are right. But why should it do so? Do all languages specify the details of how floating point input is handled by the compiler/interpreter?
- insertion 11y agoI would like to see a language use decimal by default. Under the hood, it could use floating point for certain types of calculations where less precision is required. If I want to know the answer to 0.2 + 0.1, chances are I want the answer to be 0.3. If I'm writing performance-sensitive code, maybe I can drop down a level and opt for float(0.2) + float(0.1). Are any languages doing this currently?
- dpkendal 11y agoPerl 6 uses rationals by default. They have the advantages of being base-agnostic, able to accurately represent any recurring digit expansion accurately regardless of eventual base, and also faster (since, especially if you normalize (convert to lowest terms) lazily, most operations are just a few integer instructions with no branching, looping, or bit-twiddling involved).
- grondilu 11y agoTrue. Also notice that if the user wants a floating point, the literal format is the one with the e<exponent> suffix: 0.1e0, 1e-1, 0.2e0, 2e-1 etc.
- Kristine1975 11y agoYou want COBOL. It did decimal by default 50 years ago.
- dragonwriter 11y ago> I would like to see a language use decimal by default. So, Scheme?
- dTal 11y agoScheme has rationals, but decimal literals aren't rational by default. You have to type #e in front of it, or express it as a fraction. It really ought to be fixed at the implementation level (how much stuff would it really break if floatin point errors went away?), but failing that I'd love a macro that did it for me. I can't figure out how to write one robustly.
- eccstartup 11y agoWhat a good domain name!
- erikwiffin 11y agoThat's 90% of the reason this site exists.
- Bouncingsoul1 11y agoFor C# i see a different behaviour as in his example. double test = 0.1 + 0.2; //will be 0.30000000000000004 if you check in the Debugger Debug.Print(test.ToString());//will print 0.3
- jfindley 11y agoGo is actually a lot more confusing about this than this than this page makes clear. a := .1; b := .2 fmt.Println(a+b) returns 0.30000000000000004 fmt.Println(.1+.2) returns 0.3 Even worse, this persists into comparisons: c := .3 a+b == c returns false .1+.2 == c returns true It's not a particularly big issue, mostly, but I'm sure it's confused someone before now, and will do so again. Demo code: http://play.golang.org/p/FOv0JQRQJN http://play.golang.org/p/FOv0JQRQJN
- sacado2 11y agoYay that's weird. Where's the magic?
- dmit 11y agoNumeric literals in Go are untyped until they need to be. https://blog.golang.org/constants https://blog.golang.org/constants
- 1wd 11y agoGo is specified to calculate constant expressions with higher precision (256 bits of mantissa). https://golang.org/ref/spec#Constants https://golang.org/ref/spec#Constants
- jacquesm 11y agoOne should never compare for equality on floats or doubles, with the possible exception of '0' depending on the context.
- tomp 11y agoDon't be ridiculous. It's perfectly fine if you know what you're doing. For example, when you have a limited selection of floats (e.g. hashtable keys, or only numbers between 0 and 100, accurate to 1 decimal) - in these cases, strings would work just as well, but floats are more efficient (and compare correctly).
- 11y ago
- wereHamster 11y agoIn Haskell/GHC it depends on what representation you chose. Default is Double, which exhibits this problem. But if I force it to Float I get the 'correct' result. Or if I use the 'Scientific' data type (which has arbitrary precision). Just like 'Int' vs 'Integer', where the former is restricted by the machine's word size, while the later is unbounded. Prelude> 0.1 + 0.2 :: Float 0.3 Prelude> 0.1 + 0.2 :: Double 0.30000000000000004 Prelude> :m +Data.Scientific Prelude Data.Scientific> 0.1 + 0.2 :: Scientific 0.3
- deleted 11y ago[deleted]
- headmelted 11y agoSo effectively, in Haskell, it's both and neither. A Float will round, as expected. A double will return the correct value as it, should. Shouldn't the Scientific, if it has arbitrary precision, arrive at the correct value too? Clearly the only logical conclusion is that the Glasgow compiler, at its roots, virtualizes the entire quantum mechanics model as a compilation step, enabling superposition-as-a-feature. My futile attempts at humour aside, this is quite an interesting thing to know and exactly the kind of intricate little detail I was hoping for. Tip of the hat, friend.
- wereHamster 11y agoThe Scientific type does arrive at the correct value. 0.3 is the correct answer, and Scientific gives it to you. I don't know why you would expect something else from a type which implements arbitrary precision arithmetic.
- dragonwriter 11y agoIts important to understand that 0.1 + 0.2 is actually 0.3, and Scientific is giving the correct answer. The Haskell type annotations aren't casting values that are interpreted as binary floating point (as might be the case in some languages), it is instructing the compiler how to treat the literals. Scientific is arbitrary precision decimal, so it can exactly represent 0.1 and 0.2, and return the exact result 0.3, rather than representing 0.1 and 0.2 as binary floating point approximations, adding them, and then producing some decimal approximation of the binary floating point result when asked.
- headmelted 11y agoSo I have a question. For those that arrive at the right answer, is it by mathematical correctness in the implementation or by rounding down? i.e. Which are right and which are flukey in their wrongness? Under any other circumstance I wouldn't care about this pointless detail, but seeing as how this is the top post on the front page, I'd like an excruciatingly detailed investigation please. Don't make me not get round to doing it myself, sir.
- Joeri 11y agoIn PHP's case, it converts the value to a printable (string) representation, and in so doing rounds off to a precision of 14 digits. http://lxr.php.net/xref/PHP_5_4/Zend/zend_operators.c#2142 http://lxr.php.net/xref/PHP_5_4/Zend/zend_operators.c#2142 The "mathematically" correct answer is 0.30000000000000004 according to the IEEE-754 spec.
- lsaferite 11y agoIf you want PHP to print it like the other languages you have to set the output precision high enough. The default, as you mentioned, is 14 but if you set it to 17 then you get the 'correct' output. https://3v4l.org/TRcJB https://3v4l.org/TRcJB http://php.net/manual/en/ini.core.php#ini.precision http://php.net/manual/en/ini.core.php#ini.precision
- McGlockenshire 11y agoAnother option is to use printf, as like other languages it can take a precision argument. printf('%.17f', 0.1 + 0.2); // 0.30000000000000004
- brlewis 11y agoScheme and Common Lisp arrive at the right answer to (+ 1/10 2/10) by correctness. They have internal representations for rational numbers.
- Someone 11y agoRead http://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf http://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/pr... and, if you still need more info, a few of the earlier papers it references. All of them may be correct as typically, multiple 'answers' can be correct. One could argue that given a number, one should print the shortest string that round-trips to that number, but that may mean that one prints "0.3" while the 'real' value is closer to 0.30000000000000004 or 0.29999999999999998 (a representation that one of the algorithms in the above paper gives) or possibly even equal to it. Also, some of them may be incorrect for backwards compatibility reasons. In the eyes of some, that makes them correct again. And don't get round to not doing it yourself :-)
- Walkman 11y agoHere is a very nice website that gives solution also, not just describes the problem: http://floating-point-gui.de/ http://floating-point-gui.de/ It helped me a lot when started learning.
- Kristine1975 11y agoThe author forgot Microsoft Excel. There's even a Wikipedia page about it: https://en.wikipedia.org/wiki/Numeric_precision_in_Microsoft_Excel https://en.wikipedia.org/wiki/Numeric_precision_in_Microsoft... Not that other spreadsheets (LibreOffice, Apple's Numbers) are better: They also use binary floating-point data types instead of a decimal one.
- GnwbZHiU 11y agoanyone understand why is it 0.30000000000000004, why not 0.30000000000000002 or 0.30000000000000003 or something else?
- Piskvorrr 11y agoIt's the closest binary representation. See e.g. this: https://www.reddit.com/r/javascript/comments/2scikz/eli5_why_is_this_true_01_02_030000000000000004/cnpkaug https://www.reddit.com/r/javascript/comments/2scikz/eli5_why...
- dbaupp 11y agoFloating point is (usually) about "closest representable value". That is, the normal floats form a finite subset of the real numbers, and a calculation like x + y will pick the closest element to the true result. In this case, adding the closest floating point value to "0.1" (0x1999999999999a / 2^56) and the closest one to "0.2" (0x1999999999999a / 2^55) gives 0x13333333333334 / 2^54 which is exactly 0.3000000000000000444089209850062616169452667236328125 (Rational numbers with a denominator that's a power of two have a finite decimal representation, and that's the full one for this number.) However, when printing, one is either interested in a close-enough rounded value (e.g. like some languages print 0.3 by default, or how %.3f will explicitly limit to 3 digits), or an exact representation. The exact representation should be round-trippable, so when you read it back in, you get exactly the same value. In practice this means printing a float z as a decimal value such that the closest float to the exact decimal value (i.e. as a real number) is z. Obviously the full string above works because it is exact, but it is nice to be as short as possible. In this case, the floats immediately before and after our number are exactly 0.299999999999999988897769753748434595763683319091796875 0.300000000000000099920072216264088638126850128173828125 So, only printing up to the first 4 is enough to uniquely identify our float: it is the closest one. The 0.2999* float is slightly interesting: it is the closest float to 0.3, and most environments will print "0.3" in exact mode. There's a lot of trickery/research around printing[1] and operating on floats: rounding things correctly can be highly non-trivial[2]. [1]: e.g. http://www.cs.indiana.edu/~dyb/pubs/FP-Printing-PLDI96.pdf http://www.cs.indiana.edu/~dyb/pubs/FP-Printing-PLDI96.pdf [2]: https://en.wikipedia.org/wiki/Rounding#Table-maker.27s_dilemma https://en.wikipedia.org/wiki/Rounding#Table-maker.27s_dilem...
- xedarius 11y agoWhy don't all these languages fold down to the same FPU add and hence produce the same output (on the same hardware)? Are you telling me they implement their own version of the IEEE float standard? Surely that way madness lies.
- dpkendal 11y agoThe difference is in how the result is converted to a string, not in how the result is produced.
- xedarius 11y agogotcha
- JoeAltmaier 11y agoThe difference is between the length of their floating-point number (e.g. float vs double).
- dragonwriter 11y agoIn some cases, string conversion is different, and the same calculation is going on, but the output is different. In some cases, the internal representation isn't binary floating point at all, so the errors resulting from approximating an exact decimal with a binary float don't occur.
- irascible 11y agoThey're close enough for government work.
- icemelt8 11y agoSolid proof that C# is better than JAVA. :D
- junke 11y agoThe Common Lisp version is slightly misleading because computations are made by default with single-float types, whereas there is also short-float, double-float and long-float.
- nabla9 11y agodefault for READ-DEFAULT-FLOAT-FORMAT is implementation dependent and can be changed by user. In CL type float has subtypes single-float, double-float, short-float, and long-float. "Any two of them must be either disjoint types or the same type; if the same type, then any other types between them in the above ordering must also be the same type. For example, if the type single-float and the type long-float are the same type, then the type double-float must be the same type also." If there is only one float representation it has to be `(typep x 'single-float)` but if the internal representation is different (double-float for example) it can be all of the types. At least this is how I understand the spec. http://clhs.lisp.se/Body/v_rd_def.htm#STread-default-float-formatST http://clhs.lisp.se/Body/v_rd_def.htm#STread-default-float-f... http://clhs.lisp.se/Body/t_float.htm#float http://clhs.lisp.se/Body/t_float.htm#float http://clhs.lisp.se/Body/t_short_.htm http://clhs.lisp.se/Body/t_short_.htm
- junke 11y agoIndeed. Note also that there are recommended minimum precisions and exponent sizes, which are followed in practice by CL implementations. That means that if double and long are the same type, the precision and size is at least the one recommended for long-float.
- ceronman 11y agoRecommended watch: "Demystifying Floating Point" by John Farrier at CppCon 2015. https://www.youtube.com/watch?v=k12BJGSc2Nc https://www.youtube.com/watch?v=k12BJGSc2Nc
- soegaard 11y agoAnyone care to explain the details on a Texas Instruments NSpire calculator (or CAS)? a:=0.1+0.2 b:=0.3 a-b |> 0. Using the non-exact mode.
- acqq 11y agoCalculators have traditionally used base 10 internally, not base 2, what is the base of the numbers on that TI? That's the answer, if it's base 10, .1, .2 and .3 are all exact.
- acqq 11y agoThe Wikipedia mentions base 10 with TI Basic: https://en.wikipedia.org/wiki/TI-BASIC https://en.wikipedia.org/wiki/TI-BASIC "Real numbers, using decimal floating point. These store up to 14 significant digits depending on the calculator model."
- soegaard 11y agoThis is it. An example: (1/3)*3.-1 gives -1E-14
- jwmerrill 11y agoJust a guess, but they're probably cheating the display. Try (a-b)*10^16
- soegaard 11y agoI tried some variations before I posted, but the result was just 0.
- coderdude 11y agoNaturally it's the langs you don't care about that have nailed it. Import decimal to not fail. Thanks Py. Won't forget your shortcomings ever
- NamPNQ 11y agoRust: https://play.rust-lang.org/?gist=c02ab67dab3e180b5cf9&version=stable https://play.rust-lang.org/?gist=c02ab67dab3e180b5cf9&versio...
- curun1r 11y agoIt's not quite that simple: https://play.rust-lang.org/?gist=7f6ba6bcd1c50868928a&version=stable https://play.rust-lang.org/?gist=7f6ba6bcd1c50868928a&versio...
- mpu 11y agoBc and dc do exact arithmetic.
- jamesdutc 11y agoI also posted this below as a reply. Python uses David Gay's algorithm for printing the shortest equivalent floating point representation. Implementation details and discussion are available from the Python bug tracker: https://bugs.python.org/issue1580 https://bugs.python.org/issue1580 There are a few broken links. I believe the original poster references the following paper by Robert Burger & Kent Dybvig, "Printing Floating-Point Numbers Quickly and Accurately": http://www.cs.indiana.edu/~dyb/pubs/FP-Printing-PLDI96.pdf http://www.cs.indiana.edu/~dyb/pubs/FP-Printing-PLDI96.pdf There's also a reference to the following paper by William Clinger, "How to Read Floating Point Numbers Accurately": http://www.cesura17.net/~will/professional/research/papers/retrospective.pdf http://www.cesura17.net/~will/professional/research/papers/r... ftp://ftp.ccs.neu.edu/pub/people/will/retrospective.pdf I believe this is the David Gay paper, "Correctly Rounded Binary-Decimal and Decimal-Binary Conversions": http://www.ampl.com/REFS/rounding.pdf http://www.ampl.com/REFS/rounding.pdf By the way, this has previously been discussed on HN (which is where I think I first read all of this...): https://news.ycombinator.com/item?id=2708983 https://news.ycombinator.com/item?id=2708983
- 3JPLW 11y agoThere's also the GRISU algorithm: http://dl.acm.org/citation.cfm?id=1806623 http://dl.acm.org/citation.cfm?id=1806623
- _Codemonkeyism 11y agoFWIW scala> BigDecimal("0.1") + BigDecimal("0.2") res0: scala.math.BigDecimal = 0.3 Or as I wrote in 2008 http://codemonkeyism.com/once-and-for-all-do-not-use-double-for-money/ http://codemonkeyism.com/once-and-for-all-do-not-use-double-...
- m_coder 11y agoI know that no one here cares but VBA returns 0.3 Edit: however a better test of ?.1+.2-.3 in the immediate window now returns 2.77555756156289E-17 I wondered about that first result...
- Someone 11y agoFor real fun, use Excel: =0.1+0.2-0.3 => 0 =(0.1+0.2-0.3) => 5.55112E-17 (inspired by http://www.cs.berkeley.edu/~wkahan/Mindless.pdf http://www.cs.berkeley.edu/~wkahan/Mindless.pdf)
- erikwiffin 11y agoOh Excel... I'd love to see that up on the site, mind sending me a pull request? https://github.com/erikwiffin/0.30000000000000004 https://github.com/erikwiffin/0.30000000000000004
- sdegutis 11y agoTried it in Numbers and they both say 0.0000000000000000555111512312578 EDIT: Numbers is http://www.apple.com/mac/numbers/ http://www.apple.com/mac/numbers/
- deleted 11y ago[deleted]
- speeder 11y agoThere is one langauge that once I complained to the authors that it was broken: Lua. Lua uses floating point by default, it can't make integer math at all, I made a game using Lua, back then DirectX had a bug where it would switch the floating point mode of the processor without permission, and sometimes the result was some extreme FPU imprecision. Since Lua uses only the FPU for maths, even for integers, the result was that my game had lots of extremely bizarre results sometimes on Windows (while on Linux and OSX it worked as expected), it happened only once, but I saw 5+6 result in 13... It was a really hard thing to debug, specially because of the flaming (when I asked about this on Lua IRC and forums, people flamed me endlessy, happily one guy in particular suggested me to check if it was the DX issue, and indeed it was).
- TY 11y agoVery interesting, I've never run into this, but I never used DX. For the simple example of 0.1+0.2, Lua does return 0.3 on Windows and OSX.
- mortehu 11y ago> Lua uses floating point by default, it can't make integer math at all JavaScript does this too. The fact is that with 64 bit floating point numbers, you can exactly represent every integer from -9007199254740992 to 9007199254740992, which is larger than the range of `int` on most systems anyway. 5+6 resulting in 13 is not an artifact of using floating point numbers. CPUs or GPUs don't randomly lose precision like that. 32 bit floating point numbers can exactly represent every integer from -16777216 to 16777216. See also http://www.lua.org/pil/2.3.html http://www.lua.org/pil/2.3.html
- speeder 11y agoBy the way, your reply was one of the most common replies to me that quickly turned into flaming (people offending me in all way they could to tell me Lua was perfect, and I was seeing things, because 32-bit is enough for the integers I was using...)
- recursive 11y ago> it happened only once, but I saw 5+6 result in 13 That's not the result of standard floating point arithmetic. I don't know what it is, but it's not that.
- X000 11y agoAweSome Domain Name ... :-D :v :v :v !¡!¡
- kazinator 11y agoThose languages which print 0.30000000000000004 are doing something which is silly as a default: they are printing 17 decimal digits, out of a type that only supports 15. $ txr -p '(+ .1 .2)' 0.3 Why is that? Here, the underlying type is the C double type. The printed representation is obtained according to a default precision. That default is taken from the C constant DBL_DIG. For an IEE754 double, that constant is 15. It is misleading to print more decimal digits out of a double than DBL_DIG; that is the constant which tells you how many decimal digits of precision double can reliably store. Thus I chose that constant as the default printing precision for floats: to give the programmer/user the maximum realistic precision. That is to say, print the decimal digits which are plausibly there, and not any fictional ones. 17 decimal digits requires a 57 bit mantissa -- ceil(log 10 / log 2) * 17). The 64 bit double type has only 52. So if you print 17, you're "making shit up".
- ant6n 11y agoNitpick: the 64 bit double type has a mantissa of 52 bits, but there's a 1 implied in front, so the precision is 53 bits.
- kazinator 11y agoImplied fixed material doesn't contribute precision. Otherwise we could pretend that there are twenty-four implied 1's and the precision is 76 bits. Because the implied 1 cannot be zero, it isn't a bit; it doesn't carry information. For instance if we define a four bit binary number type which has an implied 1, it can only represent values from 16 to 31. That's four bits of precision; the range is just displaced.
- ant6n 11y agoThe information of the first bit is implied via the exponent. Twenty four implied 1's would give you a precision of 76 bits, but you would restrict yourself to a very small subset of all possible numbers with that precision. EDIT: Let's put it another way. Assume you have 3 decimal digits of precision for a float. The first digit cannot be zero. Would you then claim that you don't have 3 digits of precision, but rather log(10x10x9,10) = 2.95.., because the first digit only carries 0.95.. digits of information?
- amq 11y agoThey learn this in the first lectures of a CS study.
- such_a_casual 11y agoedit: The OP has accepted my pull request and this explanation is now directly available on the website. It's a shame that the web page doesn't explain why floating point numbers are inaccurate when it comes to decimals. It's actually pretty simple. When you have a base 10 system (like ours), it can only express fractions that use a prime factor of the base. The prime factors of 10 are 2 and 5. So 1/2, 1/4, 1/5, 1/8, and 1/10 can all be expressed cleanly because the denominators all use prime factors of 10. In contrast, 1/3, 1/6, and 1/7 are all repeating decimals because their denominators use a prime factor of 3 or 7. In binary (or base 2), the only prime factor is 2. So you can only express fractions cleanly which only contain 2 as a prime factor. In binary, 1/2, 1/4, 1/8 would all be expressed cleanly as decimals. While, 1/5 or 1/10 would be repeating decimals. So 0.1 and 0.2 (1/10 and 1/5) while clean decimals in a base 10 system, are repeating decimals in the base 2 system the computer is operating in. When you do math on these repeating decimals, you end up with leftovers which carry over when you convert the computer's base 2 (binary) number into a more human readable base 10 number.
- iamphilrae 11y agoTHANK YOU! That is one of the best explanations on that matter I have seen. I've never considered why floating points are inaccurate, I just took it for a given (which I hate doing). Now I understand why, and so my own wisdom has increased ever so slightly. Today is a good day.
- acqq 11y agoSee also: http://cs.furman.edu/digitaldomain/more/ch6/dec_frac_to_bin.htm http://cs.furman.edu/digitaldomain/more/ch6/dec_frac_to_bin.... ".1 (decimal) = .00011001100110011 . . . (base 2)" Notice the repeating pattern? The exact number must have infinite number of binary digits. Wherever you cut (whichever fixed number of bits you want to keep) you lose something.
- Nemi 11y agoSo, this is a great explanation. I have never heard it expressed this way and I love it. However, I am a little confused. In your first paragraph you say that 10's prime factors are 5 and 2, so 1/10 can be expressed cleanly. In paragraph two you say that binary only has a prime factor of 2, but 10 is divisible by 2, so why doesn't 1/10 express cleanly in binary?
- ikeboy 11y agoRelevant smbc and xkcd: http://www.smbc-comics.com/?id=2999 http://www.smbc-comics.com/?id=2999 https://www.xkcd.com/217/ https://www.xkcd.com/217/
- whitej125 11y agoI remember, once upon a time... a bug where we were trying to find the average credit rating (AAA, AA+, AA, etc) of a portfolio of companies. And we had this issue where, in a simple degenerate case, the average of AA+ and AA+ became AA (AA+ is expected). In the end, it was an issue of floating point error accounting! (This was in C++ btw on a probably not-so-familiar platform). TLDR; floor(13.0) != 13 floor(13.0) == 12 Each credit rating was mapped to a integer. We'd take the floating point average of all the integers and then floor it. The integral answer would be used to map back to a credit rating. Let's say AA+ was mapped to the number 13. Well floor( (float(13) + float(13)) / 2.0) == 12. Not 13. That's because floating point 13.0 is really 12.99999999999. The fix was to add accounting for floating point error by adding in ULP (https://en.wikipedia.org/wiki/Unit_in_the_last_place https://en.wikipedia.org/wiki/Unit_in_the_last_place) which in essence tips the representation of 13.0 to 13.00000000001 (or whatever the real number is).
- nwhitehead 11y agoThis might be true on really weird platforms, but with IEEE-754 floating point this isn't true. Integers within a big range are exactly representable without any rounding error. Doing floor((float(13) + float(13))/2.0) should be exactly 13. It is entirely possible that the weird platform was supposed to be using IEEE-754 arithmetic but had a buggy math library (depressingly common).
- Angostura 11y agoInteresting that Swift and Objective-C give different results.
- jlewallen 11y agoI wish the full source for the Objective C case was provided. I'm curious to know how the value was printed.
- such_a_casual 11y agoThey do not. Open up a swift repl and try it.
- forrestthewoods 11y agoFloating point math is fun. Here's a post I did awhile back the deals with similar-ish shenanigans. https://medium.com/forrest-the-woods/perfect-prevention-of-int-overflows-f000f7e893ee https://medium.com/forrest-the-woods/perfect-prevention-of-i...
- dTal 11y agoDiscussion of this issue from 70 days ago here: https://news.ycombinator.com/item?id=10168799 https://news.ycombinator.com/item?id=10168799
- Roboprog 11y agoAlong the same lines, but slightly different emphasis (fixed precision for accounting): http://roboprogs.com/devel/2010.02.html http://roboprogs.com/devel/2010.02.html
- dzhiurgis 11y agoSalesforce Apex: system.debug( 0.1 + 0.2 ); 09:25:37:027 USER_DEBUG [3]|DEBUG|0.3 However double a = 0.1; double b = 0.2; system.debug( a + b ); 09:26:57:043 USER_DEBUG [4]|DEBUG|0.30000000000000004
- noiv 11y agoMath tells me there is an infinite number of floats between 0 and 1. 64 bits are really not enough to address that numberspace...
- nikolay 11y agoA bit unfair as Java has BigDecmial.
- pbreit 11y agoSo, best way to store currency amounts? Cents or decimal? Would the answer change based on platform or DB (i.e., Python, Postgres)?
- AlterEgo20 11y agoAny SQL DBMS is able to store and handle NUMERIC data type. It is a binary decimal with any precision you may want. Some of the DBMS's also have dedicated currency types.
- felipesabino 11y agoRecommended: Floating Point Numbers - Computerphile https://www.youtube.com/watch?v=PZRI1IfStY0 https://www.youtube.com/watch?v=PZRI1IfStY0 Tom Scott's fun and simple take on Floating Points is a good video explaining why such weird errors happen
- lovboat 11y agoAn explanation of the following useful fact:A fraction p/q is equal to a finite length floating point number in base b <=> q divides b^n <=> the prime factors of q are prime factors of b. Proof if q divides b^n, then q * c = b^n => p/q = (p * c)/(q * c) = (p * c)/b^n = (p * c)e-n in base b. Example: Express the fraction 7/18 (base 10), in base 60 and convert it to a floating point in base 60. 60 = 2^2 * 3^1 * 5^1, 18 = 2^1 * 3^2, look for c such that 18 * c is a power of 60. Observe that the factors of 60^2 all have exponents that are greater or equal than those of 18, so we can multiply 18 by the required factors to get (60^2). This way: 60^2 = (2^2 * 3 * 5)^2 = 2^4 * 3^2 * 5^2 = 18 * c = (2^1 * 3^2) * (2^3 * 3^0 * 5^2)= 18200, so we need to multiply by 200 the numerator and denominator of the initial fraction to get a new fraction whose denominator is a power of 60. Now 7/18 = (7 200)/(18 * 200) = 1400/(60^2) and 1400 = 23 * 60 + 20. Finally 7/18 = 1400/(60^2) = 0.2360 in base 60. We use the notation 00,01,02, ... 59 for the digits of base 60, so 2360 is a two digits number in base 60. The asterisk used for multiplication is not shown in HN, don't know why.
- GPGPU 11y agoLook! Php gets it right!
- acidflask 11y agoObligatory SMBC reference http://www.smbc-comics.com/?id=2999 http://www.smbc-comics.com/?id=2999