std::min/float monoid 的标识元素

luk*_*keg 5 c++ monoids

这个(非常有趣的)演讲中,演讲者提出了一个问题:

float/std::min 幺半群的 e 值是多少。

换句话说:由标准 C++ 浮点数和 std::min 操作组成的幺半群的单位元素是什么?演讲者说答案是“有趣的”。

我认为这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";
Run Code Online (Sandbox Code Playgroud)

哪个打印:

3.40282e+38
1.17549e-38
nan
nan
inf
-inf
Run Code Online (Sandbox Code Playgroud)

在测试中调用 std::min 时,我们总是得到左参数。无穷大是正确答案还是我错过了什么?

编辑:我似乎错过了一些东西。这个:

  cout << std::min(nan, inf) << "\n";
  cout << std::min(inf, nan) << "\n";
Run Code Online (Sandbox Code Playgroud)

印刷:

nan
inf
Run Code Online (Sandbox Code Playgroud)

因此,在 NaN 恶作剧的情况下,我们会根据参数的顺序得到不同的答案。

Use*_*ess 3

显然,min在仿射扩展实数(即包括 +/-inf 但不包括 NaN)上是一个幺半群。

\n

然而,比较任何东西的结果都不NaN是错误的,而是“无序的”。这意味着仅仅是 上的偏序,并且(根据 定义)因此不是幺半群。<floatstd::min<float><

\n

IEEE 754 中有一个totalOrder谓词 - 尽管我不知道它是如何在 C++ 中公开的(如果有的话)。我们可以min用 this 而不是 来编写我们自己的<,这形成一个幺半群……但它不会是std::min

\n
\n

为了确认这一点,我们可以在godbolt上编译您的代码的变体,看看它在实践中是如何实现的:

\n
    \n
  • 与 进行比较comiss,其中有可能的结果

    \n
      UNORDERED: ZF,PF,CF\xe2\x86\x90111;\n  GREATER_THAN: ZF,PF,CF\xe2\x86\x90000;\n  LESS_THAN: ZF,PF,CF\xe2\x86\x90001;\n  EQUAL: ZF,PF,CF\xe2\x86\x90100;\n
    Run Code Online (Sandbox Code Playgroud)\n

    并指定

    \n
    \n

    如果任一源操作数为 NaN(QNaN 或 SNaN),则返回无序结果。

    \n
    \n
  • \n
  • 分支已完成jbe,这将

    \n
    \n

    如果低于或等于(CF=1 或 ZF=1),则跳空。

    \n
    \n
  • \n
\n

您可以看到,该条件分支实际上将 UNORDERED 结果视为小于等于。

\n

因此,假设这是 IEEE 754 提到的无序比较的合法模型,那么应该允许两者同时存在

\n
min(min(+inf, NaN), -inf) =\nmin(+inf, -inf)           = -inf\n
Run Code Online (Sandbox Code Playgroud)\n

\n
min(+inf, min(NaN, -inf)) =\nmin(+inf, NaN)            = +inf\n
Run Code Online (Sandbox Code Playgroud)\n

这意味着min<float>不结合,因此不是幺半群。

\n