You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: text/0000-float-semantics.md
+14-2Lines changed: 14 additions & 2 deletions
Original file line number
Diff line number
Diff line change
@@ -241,13 +241,25 @@ The RFC author considers the downsides of unspecified NaN bit patterns being obs
241
241
# Prior art
242
242
[prior-art]: #prior-art
243
243
244
-
C and C++ generally avoid saying anything about signaling NaNs, and also don't talk about how NaNs are chosen. I can only assume this means they are chosen non-deterministically; that is certainly the interpretation chosen by GCC and LLVM.
244
+
C23 clarifies its stance on signaling NaNs:
245
245
246
-
GCC [says](https://gcc.gnu.org/wiki/FloatingPointMath) "Without any explicit options, GCC assumes round to nearest or even and does not care about signalling NaNs". It is unclear whether "does not care" also means "guarantees to never produce by itself", i.e. whether `0.0 / 0.0` is ever allowed to evaluate to a signaling NaN or not. If it *is* allowed to evaluate to a signaling NaN, that is probably a violation of the C standard, which guarantees that `pow(1, 0.0/0.0)` returns `1` -- but in practice, `pow(1, sNaN)` returns a NaN.
246
+
> Where specification of signaling NaNs is not provided, the behavior of signaling NaNs is implementation-defined (either treated as an IEC 60559 quiet NaN or treated as an IEC 60559 signaling NaN).
247
+
248
+
It doesn't say anything about the bit patterns inside NaNs.
249
+
This means that strictly speaking, any form of NaN boxing has to re-normalize NaNs after every single operation.
250
+
To the author's knowledge, this is not actually done in practice; code instead relies on compilers implementing a more strict semantics.
251
+
The C standard also does not state explicitly whether signaling NaNs can ever be produced by arithmetic operations, though given that the IEEE 754 semantics do not permit this to happen, presumably C does not permit this, either.
252
+
At least [two major C implementations violate this part of the spec](https://godbolt.org/z/6veef68xE).
247
253
248
254
LLVM [recently adopted](https://github.com/llvm/llvm-project/pull/66579) new NaN rules that this RFC copies exactly into Rust.
255
+
This means that even though arithmetic operations can produce signaling NaNs, there is a guarantee that signaling NaNs will never appear "out of thin air".
249
256
LLVM does not actually document that they are using IEEE float semantics, but de-facto they do on almost all targets (the exception are targets that use x87 instructions, as noted above).
250
257
258
+
GCC [says](https://gcc.gnu.org/wiki/FloatingPointMath) "Without any explicit options, GCC assumes round to nearest or even and does not care about signalling NaNs".
259
+
It is unclear whether "does not care" also means "guarantees to never produce by itself", i.e. whether `0.0 / 0.0` is ever allowed to evaluate to a signaling NaN or not.
260
+
While IEEE 754 forbids such behavior, GCC does [return signaling NaNs from some arithmetic operations](https://godbolt.org/z/6veef68xE), so it is fair to ask under which exact conditions such signaling NaNs may occur.
261
+
If `0.0 / 0.0`*is* allowed to evaluate to a signaling NaN, that is concerning for cases like `pow(1, 0.0/0.0)`, which should return `1` -- but in practice, `pow(1, sNaN)` returns a NaN.
262
+
251
263
Java requires exact IEEE 754-2008 compliance and goes through a lot of effort to realize that on 32bit x86 without SSE (see [here](https://open-std.org/jtc1/sc22/jsg/docs/m3/docs/jsgn325.pdf) and [here](https://open-std.org/JTC1/SC22/JSG/docs/m3/docs/jsgn326.pdf)). However, they do not seem to tackle the issue of specifying NaN payload bits, even though those bits [can be observed](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/lang/Float.html#floatToRawIntBits(float)).
252
264
253
265
wasm [guarantees](https://webassembly.github.io/spec/core/exec/numerics.html#nan-propagation) that "if all input NaNs are canonical, then any output NaN is canonical". Here ["canonical"](https://webassembly.github.io/spec/core/syntax/values.html#canonical-nan) is defined as a NaN with a "payload whose most significant bit 1 is while all others are 0", i.e. it matches what we call "preferred" above.
0 commit comments