IEE 754 total order in standard C++11

c++11, ieee-754

Solution

I would use:

int totalcompare(double x, double y) {
    int64_t rx, ry;

    memcpy(&rx, &x, sizeof rx);
    memcpy(&ry, &y, sizeof ry);

    if (rx == ry) return 0;

    if (rx < 0) rx ^= INT64_MAX;
    if (ry < 0) ry ^= INT64_MAX;

    if (rx < ry) return -1; else return 1;
 }

This makes `0.0` and `-0.0` compare unequal, whereas `if (x==y) return 0;` in your version makes them compare equal, meaning that your version is only a preorder. `NaN` values are above the rest and different NaNs compare different. All values comparable for `<=` should be in the same order for the above relation.

Note: the above function is C. I do not know C++.

Problem

According to the IEEE floating point wikipage (on IEEE 754), there is a total order on double-precision floating points (i.e. on C++11 implementations having IEEE-754 floats, like gcc 4.8 on Linux / x86-64). Of course, `operator <` on `double` is often providing a total order, but NaN are known to be exceptions (it is well known folklore that `x != x` is a way of testing if `x`, declared as `double x;` is a NaN). The reason I am asking is that I want to have a.g. `std::set<double>` (actually, a set of JSON-like -or Python like- values) and I would like the set to have some canonical representation (my practical concern is to emit portable JSON -same data, ordered in the same order, both on Linux/x86-64 and e.g. on Linux/ARM, even in weird cases like NaN). I cannot find any simple way to get that total order. I coded ``` // a totally ordering function, // return -1 for less-than, 0 for equal, +1 for greater int mydoublecompare(double x, double y) { if (x==y) return 0; else if (x<y) return -1; else if (x>y) return 1; int kx = std::fpclassify(x); int ky = std::fpclassify(y); if (kx == FP_INFINITE) return (x>0)?1:-1; if (ky == FP_INFINITE) return (y>0)?-1:1; if (kx == FP_NAN && ky == FP_NAN) return 0; return (kx==ky)?0:(kx<ky)?-1:1; } ``` Actually, I do know that it is not a really (mathematically speaking) total order (since e.g. bit-wise different NaN are all equal), but I am hoping it has the same (or a very close) behavior on several common architectures. Any comments or suggestion? (perhaps I should not care that much; and I deliberately don't care about signaling NaNs) The overall motivation is that I am coding some dynamically typed interpreter which persists its entire memory state in JSON notation, and I want to be sure that the persistent state is stable between architectures, in other words if I load the JSON state and dump it, it stays idempotent for several architectures (notably all of x86-64, ia-32, ARM 32 bits...).

Original source