我正在使用一些跨平台代码。在 Mac 上它是用 Clang 编译的,在 Windows 上它是用 Visual C++ 编译的。
有一个计算可能很敏感,并且触发断言的 Mac 和 Windows 之间存在差异。最终 acos 结果之间存在差异,但我不清楚为什么。
在这两个平台上,acos 的输入恰好是 -1.0f。在 Visual C++ 中,acos(-1.0f)为 3.14159274。这就是 pi 作为浮点数的值,这正是我所期望的。
但在 macOS 上:
float value = acos(-1.0f);
...计算结果为 3.1415925。这足以引发代码中的问题。acos 是一种对于 float 来说可能不精确的操作 - 我理解这一点。并且不同的编译器可以有不同的acos实现。我只是不清楚为什么 Clang 似乎对如此简单的 acos 结果有问题,而 Visual C++ 却没有。浮点数能够代表 3.14159274,但这不是我得到的结果。
可以使用以下命令从 Xcode 版本的 Clang 中获取准确/Visual C++ 对齐的值:
float value = (float)acos((double)-1.0f);
因此,我可以通过提高精度来解决这个问题,然后将值向下转换回浮点数以保留与 Windows 相同的舍入。我只是在寻找一个理由,说明当 VC++ 编译器似乎不存在精度问题时,为什么需要额外的精度。Clang/Xcode/VC++ 数学库之间也可能存在差异。我只是假设 acos(-1.0) 可能在编译器中更稳定。我在舍入模式中找不到任何差异(即使舍入不是必需的),并且 Xcode 和 Visual Studio 中的新项目也显示出相同的差异。两台机器都是英特尔的。
如果查看这些浮点值的二进制表示,您可以看到 mac/clang 的值A是 windows/msvc 的值下一个最低的浮点数B
A 3.14159250 0x40490FDA\nB 3.14159274 0x40490FDB\nRun Code Online (Sandbox Code Playgroud)\n虽然 B 最接近 \xcf\x80 的真实值,但正如 @njuffa 在他们的评论中指出的那样,它实际上大于 \xcf\x80 。
\n阅读规范,看起来acosf应该返回封闭范围 [0,\xcf\x80] 内的值。技术上A满足这个标准,但B实际上不满足。
总之 -
\nA是最接近但小于 \xcf\x80 的值B是最接近 \xcf\x80 的值这些差异可能是各个标准库实现者故意决定的结果。
\n我还观察到,这两个值都是cosfas Bothcosf(A)和cosf(B)equal的真实倒数-1.0f。
但一般来说,在任何浮点计算中依赖精确的位级精度是不明智的。如果您还没有意识到这一点,文档每个计算机科学家应该\n了解浮点运算解释了原因。
\n编辑:我很好奇,并在这里找到了可能相关的 Apple 源代码。
\n\n\nRun Code Online (Sandbox Code Playgroud)\nReturn value:\n ... \n Otherwise:\n ... \n Returns a value in [0, pi] (C 7.12.4.1 3). Note that \n this prohibits returning a correctly rounded value for acosf(-1),\n since pi rounded to a float lies outside that interval.\n
| 归档时间: |
|
| 查看次数: |
309 次 |
| 最近记录: |