根据IEEE floating point wikipage(在IEEE 754上),在双精度浮点上有一个total order(即在具有IEEE-754浮点数的C++11实现上,如Linux / x86-64上的gcc 4.8)。
当然,operator <
上的double
通常提供总顺序,但已知NaN是例外(众所周知的民间传说x != x
是一种测试x
,被宣称为double x;
是NaN的测试方式)。
我问的原因是我想要一个。 std::set<double>
(实际上,是一组类似JSON的或类似Python的值),我希望该集合具有一些规范表示(我实际关注的是发出可移植的JSON同名数据,在Linux上以相同的顺序排序) / x86-64,例如在Linux / ARM上,甚至在像NaN这样的奇怪案例中。
我找不到任何简单的方法来获得总订单。我编码了
// 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;
}
实际上,我确实知道它不是一个真正的(数学上说)总顺序(因为例如逐位不同的NaN都是相等的),但我希望它在几个常见的体系结构上具有相同(或非常接近)的行为。
有任何意见或建议吗?
(也许我不应该那么在乎;我故意不关心signaling NaNs)
总的动机是我正在编写一些动态类型的解释器,它以JSON表示法保持其整个内存状态,我想确保架构之间的持久状态是稳定的,换句话说,如果我加载JSON状态并转储它,它对于几种架构(特别是x86-64,ia-32,ARM 32位......)都是幂等的。
我会用:
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;
}
这使得0.0
和-0.0
比较不相等,而你的版本中的if (x==y) return 0;
使它们相等,这意味着你的版本只是一个预订。 NaN
值高于其余值,不同的NaN比较不同。对于<=
,所有可比较的值应与上述关系的顺序相同。
注意:上面的函数是C.我不懂C ++。