不同的数学处理器是否会得到相同的浮点运算结果?

9

我正在开发一个可在 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"吗?我问这个问题是因为我知道数学处理器可能不会返回准确的结果,我想知道在不同的处理器上是否会产生不同的结果,因为它们可能具有处理器体系结构内部的不同硬件实现IEEE浮点运算。

可以通过std::numeric_limits::epsilon<float>()获取当前平台支持的实际float精度。它可能因不同的机器架构/FPU而异。 - πάντα ῥεῖ
5
浮点数计算在同一台机器上可能会产生不一致的结果,没有理由认为在不同的操作系统上会更好。这段代码太过人工和不完整,很难猜测。显然,在尝试将更多位数存储在float中时,您已经引发了麻烦。非常不清楚截断是如何进行的。对于这个特定的值来说,它可以工作,基本不会出现编译器优化器和浮点数处理器的舍入模式弄乱结果的情况。 - Hans Passant
对于X86,内部浮点计算可以使用32位、64位或80位格式进行,具体取决于浮点控制字的设置,这可能会因编译器而异。 - rcgldr
@LưuVĩnhPhúc 如果你只是使用一个非陈旧的Java标准,而没有进一步明确你想要可重现的浮点数,那么你将无法获得可重现的浮点数。.NET甚至更糟:基本上没有办法指定你想要可重现的浮点数。而大多数其他虚拟机都是用C实现的,让他们的用户处于C的浮点数的不确定性之中。请在回答中解释你的意思或撤回你的评论。 - Pascal Cuoq
1个回答

6
很遗憾,浮点数与任意字符串之间的转换在不同平台上没有保障。原则上来说,你可能会遇到符合IEEE 754标准的处理器。该标准相当严格,定义了浮点运算。你可以对浮点数进行加/减/乘/除操作,并合理地期望在位级别上获得相同的结果。标准还定义了从/到“字符表示”的转换。原则上来说,这要求实现应该兼容,但存在一些“灵活性”。并非所有数字都必须产生相同的结果。此外,请注意默认精度和格式可能会因平台而异。话虽如此,只要(a) 控制字符串的宽度和精度而不是使用默认值 (b) 选择一个特定格式可用的最大精度范围内的精度 (c) 避免 NaN 等情况,你就有可能实现所需的结果。文章here可能会很有帮助。

.NET中将字符串转换为double的方法在某些情况下不能正确地进行四舍五入;对于一些输入字符串,当使用x87浮点数运算时,在32位模式下它们会正确地进行四舍五入,但在使用SSE浮点数运算的64位模式下则不会。所有平台都应该精确地转换每个与可精确表示的值相差1/4ulp以内的字符串,但是当给出一个距离最近可表示值接近1/2ulp的字符串时可能会有所不同(因为任何东西都不能比距离最近可表示值更远的1/2ulp,因为某些其他可表示值会更接近它)。 - supercat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接