proj-oot-ootArithmeticThoughts

"==" on floats will implement IEEE 754 totalOrder, NOT the typical IEEE 754 ==.

This is because the typical IEEE 754 floating-point == violates reflexivity b/c it specifies that NaN? != NaN?.

This is a big problem because e.g. some sort algorithms (and a zillion others) assume reflexivity in ==.

" Total-ordering predicate

The standard provides a predicate totalOrder which defines a total ordering for all floating-point data for each format. The predicate agrees with the normal comparison operations when one floating-point number is less than the other one. The normal comparison operations, however, treat NaNs? as unordered and compare −0 and +0 as equal. The totalOrder predicate orders all floating-point data strictly and totally. When comparing two floating-point numbers, it acts as the ≤ operation, except that totalOrder(−0, +0) ∧ ¬ totalOrder(+0, −0), and different representations of the same floating-point number are ordered by their exponent multiplied by the sign bit. The ordering is then extended to the NaNs? by ordering −qNaN < −sNaN < numbers < +sNaN < +qNaN, with ordering between two NaNs? in the same class being based on the integer payload, multiplied by the sign bit, of those data.[21] " [1]

EXCEPT that we will treat all NaNs? as identical, since i think some of our platforms will force us to do that, so it's more portable that way. RISC-V does not propagate NaN? payloads. WASM says "Following the recommendation that operators propagate NaN? payloads from their operands is permitted but not required." and "There is no observable difference between quiet and signalling NaNs?.", and further down on the same page the specification says, "If the payload of all NaN? inputs to the operator is canonical (including the case that there are no NaN? inputs), then the payload of the output is canonical as well. Otherwise the payload is picked non-determinsitically among all arithmetic NaNs?; that is, its most significant bit is 1" (now they say non-deterministically just to give implementations freedom to choose any NaN?, but the point is just that some implementations may not preserve non-canonical NaNs?). And CIL says, "this standard does not specify how to access the exact bit pattern of NaNs? that are created, nor the behavior when converting a NaN? between 32-bit and 64-bit representation. All of this behavior is deliberately left implementation-specific."

so

our variant will just compare all NaNs? as equal, because some platforms will not let us access details about NaNs? anyhow. I guess mb we'll provide two variants, one that puts NaNs? less than everything else, and the other that puts them greater than everything else. Although if there has to be the default, it should be the one that puts the nans at the top, b/c when you print out a nan on most platforms it says "nan", never "-nan", so this will be less surprising to people.

should we then also treat +0 and -0 as identical? hmm...

The typical IEEE 754 floating-point == will be exposed as some other function (maybe 'fcmp'). Maybe we'll even give it a compact symbol. Just not '=='.

---

unlike Python, we do not trap on floating-point division-by-zero.

---

we will provide isnan and isinf.

if a platform doesn't have an 'isnan', then we can determine that by using the platform's floating-point comparison operator and checking if x == x. If it's a NaN?, this will be FALSE, otherwise it will always be TRUE [2].

i'm not 100% sure what the proper way to make an isinf is, but i think it's probably: 0*number = 0, 0*inf = nan, 0*nan = nan. So since we already know how to identify a nan, i think we can now identify an inf too.

to distinguish -0 and +0, divide by it: 1.0/0.0 = inf, 1.0/-0.0 = -inf. Some platforms, e.g. Python, don't like even floating-point division by zero though, so watch out. Python has math.copysign though.

---