问题描述
float / std :: min id半群的e值是什么。
换句话说:由标准C ++浮点数和std :: min操作组成的monoid的标识元素是什么?演讲者说答案很“有趣”。
我认为std::numeric_limits<float>::infinity()
应该是答案,如代码所示:
const auto max = numeric_limits<float>::max();
const auto min = numeric_limits<float>::min();
const auto nan = numeric_limits<float>::signaling_NaN();
const auto nan2 = numeric_limits<float>::quiet_NaN();
const auto inf = numeric_limits<float>::infinity();
const auto minus_inf = -inf;
cout << std::min(max,inf) << "\n";
cout << std::min(min,inf) << "\n";
cout << std::min(nan,inf) << "\n";
cout << std::min(nan2,inf) << "\n";
cout << std::min(inf,inf) << "\n";
cout << std::min(minus_inf,inf) << "\n";
哪些印刷品:
3.40282e+38
1.17549e-38
nan
nan
inf
-inf
在测试中调用std :: min时,总是会得到left参数。无限答案是正确的答案还是我错过了什么?
编辑:我似乎错过了一些东西。这个:
cout << std::min(nan,nan) << "\n";
打印:
nan
inf
因此,对于NaN假名,我们会根据参数的顺序获得不同的答案。
解决方法
显然,在仿射扩展的实数(即,包括+/- inf但不包括NaN)上的min
是一个类半群。
但是,将任何内容与NaN
进行比较的结果是不是否,而是“ unordered”。这意味着<
只是float
上的偏序,因此std::min
(根据<
定义)不是一个等分线。
IEEE 754中有一个totalOrder
谓词-尽管我完全不知道它在C ++中是如何公开的。我们可以这样写而不是min
来写自己的<
,而将形成一个类半身像……但不是std::min
。
为进行确认,我们可以在godbolt上编译您的代码的变体,以查看在实践中如何实现该代码:
-
使用
comiss
完成比较,可能会得出结果UNORDERED: ZF,PF,CF←111; GREATER_THAN: ZF,CF←000; LESS_THAN: ZF,CF←001; EQUAL: ZF,CF←100;
并指定
如果任一源操作数是NaN(QNaN或SNaN),则返回无序结果。
-
使用
jbe
完成分支,如果小于或等于CF = 1或ZF = 1,则跳短。
您可以看到,此条件分支实际上将UNORDERED结果视为小于和相等。
因此,假设这是IEEE 754提到的无序比较的合法模型,则应允许两者都具有
min(min(+inf,NaN),-inf) =
min(+inf,-inf) = -inf
和
min(+inf,min(NaN,-inf)) =
min(+inf,NaN) = +inf
这意味着min<float>
不具有关联性,因此也不是monoid。