11 ms·
0.1 and 0.2 Returns 0.30000000000000004 (2018)
- arnon 5y agoFloating point considered harmful Edit: this is not a blanket statement. It was meant in the context.
- phoe-krk 5y agoMisunderstanding floating point is more harmful than floating point itself.
- arnon 5y agoHence why it's harmful.
- MaxBarraclough 5y agoFloating point arithmetic powers everything from computer graphics to weather simulations. Seems rather silly to dismiss it as an anti-pattern.
- OskarS 5y agoFloating point is fine. Non-integers are inherently tricky to represent, especially when you have to pack it into 32 bits. You could maybe quibble with some of the decisions around NaN and denormals and things like that, but mostly IEEE-754 got it right. There's a reason it's been the standard for three and a half decades now, and it's served the computer industry very well. Incidentally: the fact that 0.1+0.2 does not equal 0.3 is not something you could quibble with, that is absolutely reasonable for a floating point standard. It would be insanity to base it off of base 10 instead of base 2.
- aidenn0 5y agoOf course it shouldn't be base 10. It should be base 60. That has more prime factors and wastes fewer bits than BCD does.
- lmilcin 5y agoOr base 256 so that it fits a byte efficiently. Oh... wait...
- UncleMeat 5y agoI think one of the problems today is that floating point remains the default even for scripting languages like python. I'd wager that the huge majority of users of floating point arithmetic in their programs actually want correct math rather than efficient operations. This feels a bit like Random vs SecureRandom. So many people use the default and then accidentally shoot themselves in the foot. IMO, for scripting languages we should have infinite precision math by default and then be able to use floating point if you really care about speed.
- edflsafoiewq 5y agoWhat precise number representation do you want that's free of such "surprises"?
- lmilcin 5y agoThere exists no representation without "surprises" and it is easy to show why that must be. The closest you can get is some systems like Matlab/Octave that specialize in working with numbers.
- lifthrasiir 5y agoThis is not a trivial decision because rational numbers can have an unbounded denominator and it can cause a serious performance problem. Python explicitly ruled rational numbers out due to this issue [1]. There are multiple possible answers: - Keep rational numbers; you also have an unbounded integer so that's to be expected. (Well, unbounded integers are visible, while unbounded denominators are mostly invisble. For example it is very rare to explicitly test denominators.) - Use decimal types with precision controlled in run time, like Python `decimal` module. (That's still inexact, also we need some heavy language and/or runtime support for varying precision.) - Use interval arithmetic with ordinary floating point numbers. (This would be okay only if every user knows pitfalls of IA: for example, comparison no longer returns true or false but also "unsure". There may be some clever language constructs that can make this doable though.) - You don't have real numbers, just integers. (I think this is actually okay for surprisingly large use cases, but not all.) [1] https://python-history.blogspot.com/2009/02/early-language-design-and-development.html https://python-history.blogspot.com/2009/02/early-language-d... (search for "anecdote")
- lmilcin 5y ago"People repeating stuff without understanding it considered harmful." Floating point is extremely useful. Too bad so many people have no idea how and when to use it. Including some people that design programming languages. Please, tell me, mister, how would you perform complex numerical calculations efficiently? I guess we should just forget about drones and bunch other stuff because 90% of developers have no clue how to use FP?
- lifthrasiir 5y ago> Please, tell me, mister, how would you perform complex numerical calculations efficiently? If your calculation turned out to be incorrect it doesn't matter if it's efficient. Correct FP calculation requires error analysis, which is a concrete definition of "how to use it". If you mostly use packaged routines like LAPACK, then you don't exactly need FP; you need routines that internally use FP.
- lmilcin 5y ago> Correct FP calculation requires error analysis No, it does not. Please, don't make it seem harder than it needs to. 99% applications, if you don't do anything stupid you are completely fine. If you care for precision so much the last digit make difference for you you are probably one of very few cases. I remember somebody giving an example circumference of solar system showing uncertainty of the value of Pi available as FP to cause couple centimeters of error at the orbit of Pluto, or something like that. (Edit: found it: https://kottke.org/16/03/how-many-digits-of-pi-does-nasa-use https://kottke.org/16/03/how-many-digits-of-pi-does-nasa-use) Most of the time floating point input is already coming with its own error, you are just adding calculation error to the input uncertainty. But the calculation error is so much smaller than in most cases it is safe to ignore it. For example, if you program a drone, you have readings from IMU which have not nearly the precision of the double or even float you will be working on. There is also various techniques of ordering the operations to minimize the resulting error. If you are aware which kinds of operations in which situations can cause huge resulting error it is usually very easy to avoid it. Only very special case is if you try to subtract two values calculated separately and matching almost exactly. This should be avoided.
- dragonwriter 5y agoNot so much floating point as “using float point type for exact decimal literals”.
- arnon 5y agoFair...
- bidirectional 5y agoNot at all. For all it's faults, floating point is incredibly fast. It's not some convenience hack that we lazy programmers have come up with, it's an incredibly quick way to do numerical computation. It will always have it's place (sometimes even in finance to represent money, to many people's shock).
- lifthrasiir 5y agoTo add to that, in modern processors FP calculation is faster than integer calculation, both in terms of latency and throughput (as long as you don't hit subnormal numbers). This is very unintuitive and mostly due to disproportional demands.
- hprotagonist 5y agoIt sure does: https://0.30000000000000004.com/ https://0.30000000000000004.com/
- RedShift1 5y agoGod I love that the Internet does things like this. Thanks, this put a smile on my face today.
- tyingq 5y agoTheir summary of Mysql 5.6 (https://0.30000000000000004.com/#mysql https://0.30000000000000004.com/#mysql) isn't telling the whole story. "SELECT .1 + .2;" does return 0.3 However, CREATE TABLE t1 (f FLOAT); INSERT INTO t1 VALUES(0.1),(0.2); SELECT SUM(f) FROM t1; // returns 0.30000000447034836 Which feels odd to me. http://sqlfiddle.com/#!9/2e75e/3 http://sqlfiddle.com/#!9/2e75e/3
- lsb 5y agoYou're at 32-bit precision there.
- OskarS 5y agoNot in Raku it doesn't! > 1.1 + 2.2 3.3 > 1.1 + 2.2 == 3.3 True EDIT: to be clear: this is not because Raku is magic, it's because Raku defaults to a rational number type for decimal literals, which is arguably a much better choice for a language like Raku.
- pvorb 5y agoAhem, this is about 0.1 + 0.2. I think Raku also uses IEEE 754 double precision floating point numbers for the Num type, no? Edit: it seems that Raku uses rationals as a default [1], so it doesn't suffer from the same problem by default. [1]: https://0.30000000000000004.com/#raku https://0.30000000000000004.com/#raku
- OskarS 5y agoOh, missed that, it's usually 1.1 + 2.2 in these kinds of discussions. Yeah, exactly, Raku defaults to a rational number type for these kinds of numbers. I honestly think that is a perfectly fine way to do it, you're not using Raku for high performance stuff anyway. It's not so different from how Python will start to use arbitrarily sized integers if it feels it needs to. Raku by default will convert it to a float if the denominator gets larger than a 64-bit int, but there's actually a current pull request active that lets you customize that behavior to always keep it as a Rat. Really interesting language, Raku!
- espadrine 5y agoThe same goes in Common Lisp, but for very different reasons: * (= (+ 0.1 0.2) 0.3) T In Common Lisp, there is a small epsilon used in floating-point equality: single-float-epsilon. When two numbers are within that delta, they are considered equal. Meanwhile, in Rakudo, 0.1 is a Rat: a rational number where the numerator and denominator are computed. You can actually get the same underlying behavior in Common Lisp: (= (+ 1/10 2/10) 3/10) Sadly, not many recent languages have defaults as nice as those. Another example is Julia: julia> 1//10 + 2//10 == 3//10 true IMO, numerical computations should be correct by default, and fast in opt-in.
- ChrisLomont 5y ago
- phoe-krk 5y ago[2018]
- zamadatix 5y agoI've seen a lot of stuff on getting the shortest representation that is equal to the floating point value back but what about finding the minimum/maximum representation that is equal to a given value?
- kccqzy 5y agoThat's a rather easier problem in comparison. Just use the nextafter function in the standard library to figure out the next representable number. Then try not to exceed half of the difference using string processing.
- zamadatix 5y agoAh "nextafter" is indeed what I was looking for it just isn't in the JS standard library or Python version I use. Google has plenty examples of the function once you know what it's called though. Complexity wise that actually seems to give an equally simple "shortest answer" method - nextafter up and down and using text processing find the first digit that changes, see if it can be zero, if not choose the lowest value it can be an increment by one, remove the rest of the string accordingly, and right trim any 0s from the resulting.
- RcouF1uZ4gsC 5y agoThis is pretty much the same problem as what does 1/3 + 1/3 = in decimal. You are specifying fractions that don’t have an exact finite representation in that base (base 10 with 1/3) and (base 2 with 0.1 or 1/10). With proper rounding and I/O these are not generally an issue.
- deleted 5y ago[deleted]
- kazinator 5y agoThis just has to do with printing. This is the TXR Lisp interactive listener of TXR 256. Quit with :quit or Ctrl-D on an empty line. Ctrl-X ? for cheatsheet. TXR works even if the application surface is not free of dirt and grease. 1> (+ 0.1 0.2) 0.3 OK, so then: 2> (set *print-flo-precision* 17) 17 3> (+ 0.1 0.2) 0.30000000000000004 But: 4> 0.1 0.10000000000000001 5> 0.2 0.20000000000000001 6> 0.3 0.29999999999999999 I.e. 0.1 isn't exactly 0.1 and 0.2 isn't exactly 0.2 in the first place! The misleading action is to compare the input notation of 0.1 and 0.2 to the printed output of the sum, rather than consistently compare nothing but values printed using the same precision. The IEEE double format can store 15 decimal digits of precision such that all those decimal digits are recoverable. If we print values to no more than 15 digits, then things look "artificially clean" for situations like (+ 0.1 0.2). I made *print-flo-precision* have an initial value of 15 for this reason. The 64 bit double gives us 0.1, 0.2 and 0.3 to 15 digits of precision. If we round at that many digits, we don't see the trailing junk of representational error. Unfortunately, to 15 digits of precision, the data type gives us two different 0.3's: the 0.299999... one and the 0.3.....04 one. Thus: 7> (= (+ 0.1 0.2) 0.3) nil That's the real kicker; not so much the printing. This representational issue bites you regardless of what precision you print with and is the reason why there are situations in which you cannot compare floating-point values exactly.
- lmilcin 5y ago> The misleading action is to compare the input notation of 0.1 and 0.2 to the printed output of the sum, rather than consistently compare nothing but values printed using the same precision. I think the problem is the act of caring for the least significant bits. If you care for least significant bits of a floating point number it means you are doing something wrong. FP numbers should be treated as approximations. More specifically, the problem above is assuming that floating point addition is associative to the point of giving you results that you can compare. In floating point order of operations matters for the least significant bits. FP operations should be treated as incurring inherent error on each operation. IEEE standard is there to make it easier to do repeatable calculations (for example be able to find regression in your code, compare against another implementation) and for you to be able to reason about the magnitude of the error.
- crazygringo 5y agoIndeed, and therefore: 0.1 + 0.2 != 0.3 You can check it in the JavaScript console. This actually makes me wonder if anyone's ever attempted a floating-point representation that builds in an error range, and correctly propagated/amplified error over operations. E.g. a simple operation like "1 / 10" (to generate 0.1) would be stored not as a single floating-point value, but really as the range between the closest representation greater than and less than it. The same with "2 / 10", and then when asking if 0.1 + 0.2 == 0.3, it would find an overlap in ranges between the left-hand and right-hand sides and return true. Every floating-point operation would then take and return these ranges. Then floating point arithmetic could be used to actually reliably test equality without ever generating false negatives. And if you examined the result of calculation of 10,000 operations, you'd also be able to get a sense of how off it might maximally be. I've search online and can't find anything like it, though maybe I'm missing an important keyword.
- AnimalMuppet 5y agoBut what you would actually get is something like this: x---0.1 + 0.2 ---x x---0.3---x That is, the range of 0.1 + 0.2 would be wider than the range of 0.3. And now what do you do? There is overlap, so are they equal? But there are parts that don't overlap, so are they different?
- Nullabillity 5y agoMake equality checks illegal, and instead define specific operations for contains and overlaps.
- crazygringo 5y agoWell right now you basically can't ever check for equality with floating-point arithmetic and trust that two numbers that should intuitively be equal are reported as equal. For me, floating-point equality would be if there are any parts that overlap. Basically "=" would mean "to the extent of the floating-point accuracy of this system, these values could be equal". If you're doing a reasonably limited number of operations with values reasonably larger than the error range, then it would meet a lot of purposes -- you can add 0.5 somewhere in your code, subtract 0.5 elsewhere, and still rely on the value being equal to the original.
- deleted 5y ago[deleted]
- arduinomancer 5y agoDoes this mean I could write a calculator in JavaScript which is more accurate than the language but not as fast? For example: just treat numbers as strings and write code that adds the digits one by one and does the right carries Now that I think about it, is this the whole point of the Java BigDecimal class?
- jeffbee 5y agoYes, and it would be inexcusable malpractice to implement a calculator using the native floating-point type.
- spicybright 5y agolol, malpractice. What if you want a calculator that specifically uses native floating point math, like to aid in programming, or just playing with the datatype?
- dsego 5y agoIt's been done, there are libraries out there.
- teachingassist 5y agoYou can likely do better than this within rational numbers by working with integer numerator and denominator; you'll still have to make compromises for irrational numbers.
- wodenokoto 5y agoIn python, 0.3 prints as 0.3, but it's a double, so it should be 0.299999999999999988897769753748434595763683319091796875 (according to the article, and the 0.1+0.2 != 0.3 trick also works) What controls this rounding? e.g., in an interactive python prompt i get: >>> b = 0.299999999999999988897769753748434595763683319091796875 >>> b 0.3
- has2k1 5y agoIt depends on how many decimal places you are printing >>> f'{b:.54f}' 0.299999999999999988897769753748434595763683319091796875 >>> f'{x:.16g}' 0.3 >>> f'{x:.17g}' 0.29999999999999999
- lifthrasiir 5y agoIt is the shortest decimal number that converts back to that exact FP number. There are tons of complex algorithms for that [1]. [1] See my past comment for the overview: https://news.ycombinator.com/item?id=26054079 https://news.ycombinator.com/item?id=26054079
- young_unixer 5y agoIsn't that essentially lying to the user?
- lifthrasiir 5y ago0.299999999999999988897769753748434595763683319091796875 suggests 54 fractional digits of precision, which is misleading. 0.29999999999999998 or 0.29999999999999999 are less misleading but wasteful. Remember they are not only visible to users but can be serialized in decimal representations (thanks to, e.g. JSON). In fact, most uses of FP are essentially lies, providing an illusion of real numbers with a limited storage. It is just a matter of choosing which lie to keep.
- worik 5y agoGolly. Surprised by floating point arithmetic? 1.99999999.... == 2.0 There are limits to computer representation of floating point numbers. Computers are finite state, floating point numbers are not. sigh
- bhaak 5y agoYou mean "real numbers". Floating point numbers are one way of approximating real numbers on computers.
- worik 5y agoYes.
- chrisseaton 5y ago> Computers are finite state, floating point numbers are not. No, floating point numbers are finite state. That’s the whole point behind this discussion. There are only so many possible floating point numbers representable in so many bits. I never understand this confusion - you have finite memory - with this you can only represent a finite set of real numbers. So of course all the real numbers can’t be mapped directly.
- caf 5y agoI understand the confusion. It occurs when people haven't fully grokked that floating point numbers generally use binary representation, and that the set of numbers that can be represented with a finite number of decimal digits is distinct from the set of numbers that can be represented with a finite number of binary digits. People generally know that they can't write down the decimal value of 1÷3 exactly - they just haven't considered that for the same reason you can't write down the binary value of 1÷10 exactly either. This confusion is also helped along by the fact that the input and output of such numbers is generally still done in decimal, often rounded, that both decimal and binary can exactly represent the integers with a finite number of digits, and that the set of numbers exactly representable with in a finite decimal expansion is a superset of those exactly representable in a finite binary expansion (since 2 is a factor of 10).
- bluenose69 5y agoIn R, there are functions for practical equality (to within a tolerance that makes sense on the local machine), e.g. > all.equal(0.1+0.2,0.3) [1] TRUE and functions for actual equality, e.g. > identical(0.1+0.2,0.3) [1] FALSE
- wruza 5y agoSee also https://stackoverflow.com/a/253874 https://stackoverflow.com/a/253874
- globular-toast 5y agoWas the title of this post automatically generated? Why did it turn "0.1 + 0.2" into "0.1 and 0.2"?
- dang 5y agoRelated past threads (not about this article): 0.30000000000000004 - https://news.ycombinator.com/item?id=21686264 https://news.ycombinator.com/item?id=21686264 - Dec 2019 (402 comments) 0.30000000000000004 - https://news.ycombinator.com/item?id=14018450 https://news.ycombinator.com/item?id=14018450 - April 2017 (130 comments) 0.30000000000000004 - https://news.ycombinator.com/item?id=10558871 https://news.ycombinator.com/item?id=10558871 - Nov 2015 (240 comments) 0.30000000000000004 - https://news.ycombinator.com/item?id=1846926 https://news.ycombinator.com/item?id=1846926 - Oct 2010 (128 comments) Resisting temptation to list floating-point math threads because there are so many: https://hn.algolia.com/?dateRange=all&page=0&prefix=true&query=floating%20point%20comments%3E20&sort=byDate&type=story&storyText=none https://hn.algolia.com/?dateRange=all&page=0&prefix=true&que...
- IncRnd 5y agoThis is why games and certain other types of coding use fixed point arithmetic.
- The_rationalist 5y agoThe problem is solved in many languages such as Java by suffixing F to the numbers.
- lelf 5y agoCoq < Compute 0.1. Toplevel input, characters 8-11: > Compute 0.1. > ^^^ Warning: The constant 0.1 is not a binary64 floating-point value. A closest value 0x1.999999999999ap-4 will be used and unambiguously printed 0.10000000000000001. [inexact-float,parsing] = 0.10000000000000001 : float
- tmabraham 5y agohttps://twitter.com/qntm/status/1381346718919356416 https://twitter.com/qntm/status/1381346718919356416 Hahahaha!
- gravelc 5y agoAs an aside, just finish qntm's spectacularly good 'There Is No Antimemetics Division". Highly worth a read if you're after some highly original sci-fi.
- kungito 5y agoHN is more and more like first semester coding class where the professor always tells the "fun facts" but we have to be in the same class every year
- tediousdemise 5y agoReminds me of long-standing problems in mathematics. The problems will forever be amusing until some dark horse comes out of nowhere with a formal proof/solution that stuns the academic community.
- BeetleB 5y agoEternal September?
- messe 5y agoIf only the mind was spotless.
- enriquto 5y agojust let the lucky thousand of today have their fun!
- nomel 5y agoYou might be surprised how many people don’t understand the bit level basics these days. They’re not really the focus anymore, and they probably shouldn’t be. The point of advancing technology is to push the mundane, low level, difficulties away to make bigger concepts/abstractions easier to piece together and mentally bear. From what I’ve seen with most recent grads, the education is shifting more and more towards algorithms, with experience mostly involving the use of existing libraries/frameworks, rather than lower level implementations that us “old timers” were forced to implement ourselves, thanks to lack of accessibility to freely usable code. I think GitHub, StackOverflow, and Google have changed the mental model of software development, significantly. I don’t think that’s a bad thing at all since it should free up some beans, especially for someone new to the field. Not knowing this will bite you eventually, but it’s fairly trivial to work out.
- 29athrowaway 5y agoDo it in Python and many other languages you'll get the same result. >>> 0.1 + 0.2 0.30000000000000004 That's the expected behavior of floating-point numbers, more specifically, IEEE 754. If you don't want this to happen, use fixed-point numbers, if they're supported by your language, or integers with a shifted decimal point. Personally, I think if you don't know this, it's not safe for you to write computer programs professionally, because this can have real consequences when dealing with currency.
- bassdropvroom 5y agoSuper interesting. I'd noticed this behaviour previously, but never knew how or why this was the case (and not really bothered to search for it either). Thanks!
- dec0dedab0de 5y agoI think high level languages shouldn't even have floats, unless they're a special type for doing floating point math. Specifically I'm thinking about python, the literal x.x should be for Decimal and float should have to be imported to be used as an optimization if you need it.
- Black101 5y agoits ok... there are bigger mistakes/bugs at stock brokers
- georgeburdell 5y agoI use this as one of my interview questions (in a piece of code where it would run correctly if 0.1 + 0.2 = 0.3). Maybe 1/3 of interviewees recognize the cause, and maybe half of those can actually explain why and how to mitigate it. I work in scientific computing so it's absolutely relevant to my work
- neilv 5y agoOne of the many reasons I think we all would've been better off, had Brendan Eich decided he'd been able to simply use Scheme within the crazy time constraint he'd been given, rather than create JavaScript, :) is that Scheme comes with a distinction between exact and inexact numbers, in its numerical tower: https://en.wikipedia.org/wiki/Numerical_tower https://en.wikipedia.org/wiki/Numerical_tower One change I'd consider making to Scheme, and to most high-level general-purpose languages (that aren't specialized for number-crunching or systems programming), is to have the reader default to reading numeric literals as exact. For example, the current behavior in Racket and Guile: Welcome to Racket v7.3. > (+ 0.1 0.2) 0.30000000000000004 > (+ #e0.1 #e0.2) 3/10 > (exact->inexact (+ #e0.1 #e0.2)) 0.3 So, I'd lean towards getting the `#e` behavior without needing the `#e` in the source. By default, that would give the programmer in this high-level language the expected behavior. And systems programmers, people writing number-crunching code, would be able to add annotations when they want an imprecise float or an overflowable int. (I'd also default to displaying exact fractional rational numbers using familiar decimal point conventions, not the fractional form in the example above.)
- 29athrowaway 5y agoMany languages make a distinction between floating-point numbers and fixed-point numbers. Fixed-point numbers (e.g.: "Decimal" / "BigDecimal" in Java) do not suffer from this problem.
- Wowfunhappy 5y agoThis would make particular sense in a language like python, which no one (should?) be using for systems programming.
- neilv 5y agoAgreed. Though, for reasons, I had to write essentially a userland device driver in Python (complete with buffer management and keyboard decoder). It was rock-solid in production, in remote appliances, and I was very glad Python was up to that. :)
- vincent-manis 5y ago
- cratermoon 5y agoIf you think that is crazy, check out Muller's Recurrence: https://scipython.com/blog/mullers-recurrence/ https://scipython.com/blog/mullers-recurrence/
- lossolo 5y agoIf anyone would like to know more then read this paper from 1991 by David Goldberg What every computer scientist should know about floating-point arithmetic, very accessible content even if you are not from CS field. http://pages.cs.wisc.edu/~david/courses/cs552/S12/handouts/goldberg-floating-point.pdf http://pages.cs.wisc.edu/~david/courses/cs552/S12/handouts/g...
- IEEE754 5y ago> does not interpret the 0.1 as the real number The focus should be on _rational_ numbers. This particular example is all about representation error - precision is implicated, but not the cause. Ignore precision for a second: The inputs 0.1 and 0.2 are intended to be _rational_. This means they can be accurately represented finitely (unlike an irrational number like PI). Now when using fractions they can _always_ be accurately represented finitely in any base: 1/10= base 10: 1/10 base 2: 1/1010 2/10= base 10: 2/10 base 2: 10/1010 The neat thing about rationals, is that when using the four basic arithmetic operations: two rational inputs will always produce one rational output :) this is relevant: 1/10 and 2/10 are both rationals, there is no fundamental reason that addition cannot produce 3/10. When using a format that has no representation error (i.e fractions) the output will be rational for all rational inputs (given enough precision, which is not a realistic issue in this case). When we add these particular numbers in our heads however, almost everyone uses decimals (base 10 floating point), and in this particular case that doesn't cause a problem, but what about 1/3? This is the key: rationals cannot always be represented finitely in floating point formats, but this is merely an artifact of the format and the base. Different bases have different capabilities: 1/10= base 10: 0.1 base 2: 0.00011001100110011r 2/10= base 10: 0.2 base 2: 0.00110011001100110r 1/3= base 10: 0.33333333333333333r base 2: 0.01010101010101010r IEEE754 format is a bit more complicated than above, but this is sufficient to make the point. If you can grok that key point (representation error), here's the real understanding of this problem: Deception 1: The parser has to convert '0.1' decimal into base 2, which will cause the periodic significand '1001100110011' (not accurately stored at any precision)... yet when you ask for it back, the formater magically converts it to '0.1' why? because the parser and formater have symmetrical error :) This is kinda deceptive, because it makes it look like storage is accurate if you don't know what's going on under the hood. Deception 2: Many combinations of arithmetic on simple rational decimal inputs also have rational outputs from the formatter, which furthers the illusion. For example, nether 0.1 or 0.3 are representable in base 2, yet 0.1 + 0.3 will be formatted to '0.4' why? It just happens that the arithmetic on those inaccurate representations added up to the same error that the parser produces when parsing '0.4', and since the parser and formatter produce symmetric error, the output is a rational decimal. Deception 3: Most of us grew up with calculators, or even software calculator programs. All of these usually round display values to 10 significant decimals by default, which is quite a bit less than the max decimal output of a double. This always conceals any small representation errors output by the formatter after arithmetic on rational decimal inputs - which makes calculators look infallible when doing simple math.
- kissgyorgy 5y agohttps://floating-point-gui.de/ https://floating-point-gui.de/
- lamontcg 5y agoYour monthly HackerNews reminder that machine epsilon is a thing.
- PaulHoule 5y agohttps://www.crockford.com/dec64.html https://www.crockford.com/dec64.html and see me in the morning.
- selcuka 5y agoObligatory SMBC [1] and xkcd [2]: [1] https://www.smbc-comics.com/?id=2999 https://www.smbc-comics.com/?id=2999 [2] https://xkcd.com/2170/ https://xkcd.com/2170/
- deleted 5y ago[deleted]
- hnjst 5y agoI guess that can be tracked back to the use of fancy new buggy tools ;) bc <<< "0.1 + 0.2" .3 bc <<< "1.0E4096 +1 -1.0E4096" 1.000000 node -e "console.log(1.0E128 +1 -1.0E128)" 0 python -c "print(1.0E128 +1 -1.0E128)" 0.0