从i386移动到x86_64时的浮点精度
我有一个为Linux x86 32位开发的应用程序。 根据结果,有许多浮点运算和大量测试。 现在我们将它移植到x86_64,但测试结果在这个架构中是不同的。 我们不希望为每个体系结构保留一组单独的结果。
根据GCC简介 – 对于GNU编译器gcc和g ++ ,问题是X86_64中的GCC假设fpmath = sse而x86假定fpmath = 387 。 387 FPU对所有操作使用80位内部精度 ,仅将结果转换为给定的浮点类型(float,double或long double),而SSE使用操作数的类型来确定其内部精度。
在编译我自己的代码并且我的所有操作都正常工作时,我可以强制-mfpmath = 387 ,但每当我调用一些库函数(sin,cos,atan2等)时,结果再次出错。 我认为这是因为libm是在没有fpmath覆盖的情况下编译的。
我尝试使用387仿真自己构建libm(glibc),但它导致了很多崩溃(不知道我做错了什么)。
有没有办法强制进程中的所有代码在x86_64中使用387仿真? 或者也许某些库在两种体系结构上都返回与libm相同的值? 有什么建议?
关于“你需要80位精度”的问题,我不得不说这不是个别操作的问题。 在这个简单的情况下,差异非常小,没有区别。 但是,当复合很多操作时,错误会传播,并且最终结果的差异不再那么小,并且会产生影响。 所以我想我需要80位精度。
我说你需要修理你的测试。 如果你假设浮点数学是准确的,你通常会让自己失望。 而不是测试确切的相等性,测试它是否足够接近预期的结果。 毕竟,你发现的不是一个bug,所以如果你的测试报告错误, 测试是错误的。 ;)
正如您所知,您依赖的每个库都将采用SSE浮点,因此除非您计划手动编译所有内容 ,现在和永久,只需将FP模式设置为x87,您最好不要处理现在问题,只是接受FP数学不是100%准确,并且通常不会在两个不同的平台上产生相同的结果。 (我相信AMD CPU的产量在x87数学上也略有不同)。
你绝对需要 80位精度吗? (如果是这样,除了自己编译所有内容以使用80位FP之外,显然没有太多替代方案。)
否则,调整测试以在一些小epsilon中执行比较和相等测试。 如果差异小于该epsilon,则认为这些值相等。
80位精度实际上是危险的。 问题是只要变量存储在CPU寄存器中,它就会被保留。 每当它被强制输出到RAM时,它都被截断为类型精度。 所以你可以让一个变量实际上改变它的值,即使它在代码中没有发生任何变化。
如果你想要long double
精度,对所有浮点变量使用long double
,而不是期望float
或double
有额外的魔法精度。 这真是一个明智的选择。
SSE浮点和387浮点使用完全不同的指令,因此没有办法说服SSE fp指令使用387.可能最好的处理方法是将测试套件重新调整为略有不同的结果,而不是依赖于结果与最后一位相同。