Since the first time I had Indian food sometime in 1987 I have always called naan “not a number bread” and no one has ever laughed. I feel like i may have found my people.
This doesn't work on Firefox, as it normalizes NaNs as they're extracted from ArrayBuffers. Presumably because SpiderMonkey uses NaN-boxing itself, and thus just doesn't have any way to represent actual non-canonical NaN floats.
moffkalast · 15m ago
Dammit Mozilla, first no WebGPU, now this?! /s
axblount · 1h ago
This is usually called NaN-boxing and is often used to implement dynamic languages.
I wonder if IEEE-754 designers anticipated this use case during development. Great article - this kind of "outside-the-normal-use-case" requires a very careful reading of the specifications/guarantees of the language.
addoo · 51m ago
I appreciate this article a lot more because it contains an iota of benchmarking with an explanation about why this might be more performant. Especially since my first thought was 'wouldn't this require more instructions to be executed?'
The original post seems really weird to me. I would have dismissed it as someone's hobby project, but... that doesn't seem like what it's trying to be.
amelius · 55m ago
I'm curious why we have not-a-number, but not not-a-string, not-a-boolean, not-an-enum, and not-a-mycustomtype.
dzaima · 49m ago
Because NaNs come from a standardized hardware-supported type, whereas the rest of those are largely language-specific (and you could consider null/nil as a "not-a-*" type for those in applicable languages; and there are languages which disallow NaN floats too, which completes all combinations).
Itanium had a bit for "not a thing" for integers, so the idea of hardware support for not-a-* isn't exclusive to floats, but evidently this hasn't caught on; generally it's messy because it needs a bit pattern to yoink, but many types don't have any free ones (whereas floats already needed to chop out some for infinities).
Sharlin · 42m ago
You can encode not-a-bool, not-a-(utf-8)-string and not-an-enum using one of the invalid bit patterns – that's exactly what the Rust compiler can do with its "niche optimization": https://www.0xatticus.com/posts/understanding_rust_niche/
Sharlin · 50m ago
Because IEEE 754 creators wanted to signal non-trapping error conditions for mathematically undefined operations, and they had a plenty of bit patterns to spare. Apparently back in the 70s and 80s in many cases it was preferable for a computation to go through and produce NaNs rather than trapping instantly when executing an undefined operation. I'm not quite sure what the reasoning was exactly.
usefulcat · 19m ago
C++ has std::optional for exactly that purpose.
ok_computer · 51m ago
Because representing infinity is not possible outside of symbolic logic and isn’t encodable in floats. I think it is a simple numerical reason and not a deeper computer reason.
Sharlin · 43m ago
Well, infinity is totally representable with IEEE 754 floats. For example 1.0/0.0 == +inf, -1.0/0.0 == -inf, but 0.0/0.0 == NaN.
amelius · 21m ago
A smart compiler should be able to figure out a better value for 0/0, depending on context.
For example:
for i in range(0, 10):
print(i/0.0)
In this case it should probably print +inf when i == 0.
But:
for i in range(-10, 10):
print(i/0.0)
Now it is not clear, but at least we know it's an infinity so perhaps we need a special value +-inf.
And:
for i in range(-10, 10):
print(i/i)
In this case, the value for 0/0 can be 1.
Sharlin · 20m ago
Well, it could, but that would be against the spec. The hardware implements IEEE 754, most languages guarantee IEEE 754, and transforming code so that 0.0/0.0 doesn't result in NaN would be invalid.
IncreasePosts · 50m ago
Some common numeric operations can result in non-numbers(eg division by zero - Nan or infinity).
Are there any common string operations with similar behavior?
dunham · 1h ago
I learned about this when trying to decode data from Firefox IndexedDB. (I was extracting Tana data.) Their structured clone data format uses nan-boxing for serialization.
haxiomic · 38m ago
That's curious! Does anyone know why the spec was designed to allow so many possible NaN bit patterns? Seems like just one would do!
dzaima · 33m ago
As long as you want all bit patterns to be Some float, there's not really one bit pattern you can chop out of somewhere (or, three, rather - both infinities, and NaN).
Taking, say, the 3 smallest subnormal numbers, or the three largest numbers, or whatever, would be extremely bad for allowing optimizations/algorithms/correctness checkers to reason about operations in the abstract.
AaronAPU · 1h ago
Reminds me of using the highest bit(s) of 64-bit ints to stuff auxiliary data into lockfree algorithms. So long as you’re aware of your OS environment you can enable some efficiencies you couldn’t otherwise.
eru · 56m ago
That's why OCaml has 63 bit integers by default: the language itself uses the last bit to help with GC.
https://piotrduperas.com/posts/nan-boxing
The original post seems really weird to me. I would have dismissed it as someone's hobby project, but... that doesn't seem like what it's trying to be.
Itanium had a bit for "not a thing" for integers, so the idea of hardware support for not-a-* isn't exclusive to floats, but evidently this hasn't caught on; generally it's messy because it needs a bit pattern to yoink, but many types don't have any free ones (whereas floats already needed to chop out some for infinities).
For example:
In this case it should probably print +inf when i == 0.But:
Now it is not clear, but at least we know it's an infinity so perhaps we need a special value +-inf.And:
In this case, the value for 0/0 can be 1.Are there any common string operations with similar behavior?
Taking, say, the 3 smallest subnormal numbers, or the three largest numbers, or whatever, would be extremely bad for allowing optimizations/algorithms/correctness checkers to reason about operations in the abstract.