不同的数学 CPU 会生成相同的浮点结果吗?

Will different math CPUs yield the same floating point results?

提问人: 提问时间:5/31/2014 最后编辑:zastrowm 更新时间:7/1/2016 访问量:3181

问:

我正在开发操作系统便携式软件,该软件具有必须在 Linux、UNIX 和 Windows 上运行的单元测试。

想象一下这个单元测试,它断言 IEEE 单精度浮点值 1.26743237e+015f 被转换为字符串:

void DataTypeConvertion_Test::TestToFloatWide()
{
    CDataTypeConversion<wchar_t> dataTypeConvertion;
    float val = 1.26743237e+015f;
    wchar_t *valStr = (wchar_t*)dataTypeConvertion.ToFloat(val);
    std::wcout << valStr << std::endl;
    int result = wcscmp(L"1.26743E+015", valStr);
    CPPUNIT_ASSERT_EQUAL(0, result);
    delete [] valStr;
}

我的问题是:只要浮点数是 IEEE,所有操作系统和处理器都会将浮点数转换为字符串“1.26743E+015”吗?我之所以这么问,是因为我知道数学 CPU 可能无法返回准确的结果,我想知道这是否会在不同的处理器上产生不同的结果,因为它们可能在处理器架构内部具有不同的 IEEE 浮点运算硬件实现。

C++ 精度 浮点转换

评论

0赞 πάντα ῥεῖ 5/31/2014
当前平台支持的实际精度可以通过 std::numeric_limits::epsilon<float>() 获得。对于不同的机器架构/FPU,它可能有所不同。float
5赞 Hans Passant 5/31/2014
浮点计算可能会在同一台机器上产生不一致的结果,没有理由假设它在不同的操作系统上会变得更好。该片段太人为且不完整,无法猜测。显然,您已经尝试在浮点数中存储比它能够存储的更多的数字,从而引发了麻烦。非常不清楚截断是如何执行的。它会起作用,编译器的优化器和浮点处理器的舍入模式用这个特定值搞砸结果的可能性很小。
0赞 rcgldr 5/31/2014
对于 X86,内部浮点计算可以以 32 位、64 位或 80 位格式执行,具体取决于浮点控制字的设置,这可能因编译器而异。
0赞 Pascal Cuoq 6/1/2014
@LưuVĩnhPhúc 如果你只是使用一个过时的 Java 标准,而没有进一步明确你想要可重现的浮点,你就不会得到可重现的浮点。更糟糕的是:基本上没有办法指定你想要可重现的浮点。大多数其他虚拟机都是用 C 语言实现的,让用户受制于 C 浮点变幻莫测。请在回答中解释您的意思或撤回您的评论。

答:

6赞 david.pfx 5/31/2014 #1

可悲的是,答案很可能是否定的。不能保证浮点数与任意字符串之间的转换是跨平台的。

至少原则上,您可能遇到的所有处理器都符合 IEEE 754 标准。该标准相当严格,因为它定义了浮点运算。您可以对浮点数进行加/减/倍增或除法,并合理期望在位级别跨平台获得相同的结果。

该标准还定义了与“字符表示”之间的转换。原则上,这需要符合要求的实现是兼容的,但它有“回旋余地”。并非所有数字都必须产生相同的结果。

您还应该知道,默认精度和格式可能因平台而异。

综上所述,只要 (a) 控制字符串的宽度和精度,而不是将其保留为默认值,您就可以获得所需的结果 (b) 您选择的精度完全在特定格式的最大可用范围内 (c) 避免 NaN 和类似格式。

这里的文章很有帮助。

评论

0赞 supercat 11/17/2014
将字符串转换为 的 .NET 方法并非在所有情况下都执行正确的舍入;对于某些输入字符串,当使用 x87 浮点数学时,它们将在 32 位模式下正确舍入,但在使用 SSE 浮点数学的 64 位模式下则不会。所有平台都应该精确地转换每个字符串,这些字符串距离精确可表示值的 1/4ulp 以内,但当给定一个与最接近的可表示值接近 1/2ulp 的字符串时,可能会有所不同(没有任何东西与最接近的可表示值超过 1/2ulp,因为其他一些可表示值会更接近它)double