9 ms·
Floating Point in the Browser, Part 1: Impossible Expectations
- chrisseaton 6y agoAnyone who's ever worked on programming language implementation will recognise that you will for all time get a steady stream of occasional bug reports that your floating point numbers aren't arbitrarily precise. Some language implementation bug trackers have a warning not to submit bugs for it front and centre because they get it so often.
- saagarjha 6y agoIn JavaScript I assume it’s worse because most people would assume the existence of some sort of integer type but the number silently “becomes a floating point” instead, which can be confusing.
- Gibbon1 6y agoI don't use JavaScript but JavaScript using binary floating point always makes me shake my head in disbelief. You got a language designed from the start to deal with user input that can't represent decimal numbers and fractions.
- SAI_Peregrinus 6y agoJSON Numbers are arbitrary precision floating point. JavaScript numbers aren't necessarily numeric, they can be NaN or INF. That disconnect isn't a bug, but can cause problems if you naively convert from one to the other without handling the edge cases.
- Spivak 6y agoThe problem is we’re now at the point where we have mountains of code that doesn’t handle the edge cases and very little that can be done outside of being super conservative about what send an unknown JSON parser.
- umvi 6y agoTIL JavaScipt doesn't have an integer type and uses double under the hood to store integers. Yet another footgun to add to the massive stack.
- chrisseaton 6y agoDouble represents consecutive integers up to 2^53 - that's even larger than Java's int so it's more than fine for almost all purposes.
- umvi 6y agoI can't help but compare JS to python though. For every footgun in JS, the same footgun does not exist in python including this one.
- jkaptur 6y agoInteresting - I view it the opposite way. In JavaScript, you need to know the details of exactly one numeric type: the regular, standard IEEE 754 float that's used by Java, Python, C++ (generally), and every other programming language under the sun. That's it! There is only one way to do it ;) These days, if you need huge integers, you can use BigInt, but if you want to use it in an expression that also contains floating point values, then you need to explicitly convert it. Explicit is better than implicit.
- umvi 6y agoI just find it counter intuitive, that's all. The expectation is that high level scripting languages have BigInt enabled by default (since that's what Ruby/Python do). Not so with JS. The expectation is that sorting an array of integers in place: [1,3,2,4,5,7,6,8,9,10].sort() produces an array with the numbers in ascending order (since that's what Ruby/Python do). Not so with JS (try it out). A agree there is a perfectly logical reason for every quirky behavior, but I've been surprised (in a bad way) so many times by JS's counter-intuitive behavior that I now have a mental collection of gotchas where JS deviates from expectation.
- pmarreck 6y agoI avoid FP as much as possible precisely because of these nondeterministic (at least in the practical sense) results. I use integers almost exclusively and if I need fixed point I have view code that renders things correctly (such as for currency). When Erlang didn't have a power function that didn't use floating-point (and thus resulted in rounding errors), I wrote my own: https://github.com/pmarreck/elixir-snippets/blob/master/math_integer_power.exs https://github.com/pmarreck/elixir-snippets/blob/master/math...
- recursive 6y agoIn this case you're just trading for overflow.
- saagarjha 6y agoWhat’s also interesting is how the “minimum representation needed to roundtrip a number” is actually done. There is recent (2010) research into doing this efficiently using an algorithm called Grisu: https://dl.acm.org/doi/10.1145/1809028.1806623 https://dl.acm.org/doi/10.1145/1809028.1806623. Many programming language implementations use it now for this purpose.
- ygra 6y agoActually, there's even more recent research into doing this really efficiently, using an algorithm called Ryū. [e] https://github.com/ulfjack/ryu https://github.com/ulfjack/ryu [-4] https://www.youtube.com/watch?v=kw-U6smcLzk https://www.youtube.com/watch?v=kw-U6smcLzk [1.73] https://www.youtube.com/watch?v=4P_kbF0EbZM https://www.youtube.com/watch?v=4P_kbF0EbZM
- pklausler 6y agoThe f18 Fortran compiler has a novel algorithm (calculating in base 10^16) for conversions that is fast and doesn't require big look-up tables. https://github.com/llvm/llvm-project/tree/master/flang/lib/Decimal https://github.com/llvm/llvm-project/tree/master/flang/lib/D...
- SAI_Peregrinus 6y agoI've mentioned it before, but JSON Numbers are arbitrary-precision floating-point. They can't be naively stored as JavaScript numbers in all cases, since JS numbers are IEEE754 double-precision floating point. Likewise, you can't store arbitrary JS number values in JSON Numbers, since it doesn't handle IEEE754 exception values (qNaN, sNaN, ±INF). So if you're trying to publish data from a GPS chip that reports fix failure by setting the latitude and longitude to a NaN (possibly with a failure code in the exception value) you can handle that in JS but only through some intermediate representation in JSON.
- deleted 6y ago[deleted]
- vlovich123 6y agoHonestly I think it's the biggest misfeature of JSON. Arbitrary precision numbers should have been handled differently & I've repeatedly seen JSON parsers incorrectly handle those. We're now in a situation where you can't serialize numbers you encounter daily into JSON and you can't trust that numbers you correctly serialized into JSON will be properly deserialized by the peer. I spent a lot of time writing the number handling code in PBNJSON for WebOS back in the day (IIRC there were 0 C/C++ parsers that offered correct number parsing at the time). It also makes sure to properly report overflow/underflow/failure to convert whenever you encounter situations that aren't possible (e.g. reading 32-bit number of a 64-bit int JSON, reading 64-bit integer for doubles that are out of range, etc). I'm sure I missed some corner cases though as it's insanely difficult to get every single corner case (especially with floating point).
- mormegil 6y ago> I've mentioned it before, but JSON Numbers are arbitrary-precision floating-point. They can't be naively stored as JavaScript numbers in all cases, since JS numbers are IEEE754 double-precision floating point. Well, RFC 8259 says "This specification allows implementations to set limits on the range and precision of numbers accepted." and goes on to explain interoperability with IEEE doubles.
- 6y ago
- jakub_g 6y agoThe author has many blog posts on floating point math, and they're all very interesting. If you're into the topic, you can check the tagged entries: https://randomascii.wordpress.com/category/floating-point/ https://randomascii.wordpress.com/category/floating-point/ In general the whole blog is super interesting and many times submitted to HN: https://news.ycombinator.com/from?site=randomascii.wordpress.com https://news.ycombinator.com/from?site=randomascii.wordpress...
- Spivak 6y agoI really really wish these things were errors. Data loss should require an explicit opt-in. It's easy to point to the spec and say that people should obviously know it back-and-forward but it's extremely surprising that JSON decoding is a lossy operation and you have reach not for an option flag but a whole 3rd party library to not get that behavior. JSON's arbitrary precision decimals is the silliest footgun. When every implementation implicitly defines its own valid format by way of what native types it maps it makes for a really awkward way to pass messages between two black-box systems.
- lmilcin 6y agoI feel like a lot of discussion is on floating point accuracy and artifacts and most of it misses the point completely. It doesn't help there are IEEE standards for fp calculations which are also very misunderstood. The point of these standards is to provide reproducibility and repeatability so that different types of software running on different machines or with different compilers provide same results. The goal of floating point never was to provide precise representation or calculation and in fact it is not possible to provide in general with floating point. The goal was to make it easy and relatively fast to perform real world calculations. You understand your calculator gives approximate results except for very special cases, so why would you bicker over some digits that are very far to the right of your result. It is actually much worse with calculators because they tend to employ very different calculation engines and very different precision. You can actually identify a particular model or model family of calculator by running couple calculations and finding what kind of artifacts are present in the results, exactly. Yet nobody will tell you calculators are useless as I frequently hear about floating point. I work with Java and there seems to be this movement recently where developers use arbitrary precision arithmetic to do any sort of calculation on anything without actual idea of when this is needed. Supposedly flating point is broken and cannot be trusted. Sigh...
- T-hawk 6y agoYou bicker over the digits far to the right because there tends to be ways for those inaccuracies to propagate up into your significant figures. That doesn't happen from typing a few arithmetic operations into a handheld calculator. It does in a computational environment that might be looping over and summing a million or a billion elements and applying more operations to them. It became too easy and fast to use floats for real world calculations, overstressing and exposing their inadequacies. Of course, the right solution is to use the right tool for the job: algorithms that either use a better structure than a 64-bit float, or are smartly designed enough to avoid their inadequacies. But how many developers have both enough insight and enough development time to do that? Everything is a compromise; fixed-point decimal representation is one that works for many applications.
- mehrdadn 6y agoThere's a huge difference between mathematical calculations having round-off error and computations that are not mathematical calculations exhibiting something akin to round-off error anyway. It's like giving someone a $10k check and seeing them get $9,999.99, and then getting irritated when people try to investigate what happened because it's only a penny to you. It's kind of missing the point that the error logically shouldn't be there in this situation.
- spullara 6y agoAnd now you know why the Twitter API has all IDs as both numbers and strings.