ste*_*km3 6 c++ floating-point floating-accuracy ieee-754
标准是否保证函数在所有实现中返回完全相同的结果?
以pow(float,float)32位IEEE浮点数为例.如果传入相同的两个浮点数,则所有实现的结果是否相同?
或者是否有一些灵活性,标准允许根据用于实现的算法的微小差异pow?
Cor*_*lks 18
不,C++标准不要求cmath函数的结果在所有实现中都是相同的.对于初学者,您可能无法获得IEEE-754/IEC 60559浮点运算.
也就是说,如果一个实现确实使用IEC 60559并定义__STDC_IEC_559__,那么它必须遵守C标准的附录F(是的,你的问题是关于C++,但C++标准遵循C标准的C标准math.h).附件F规定:
- 该
float类型符合IEC 60559单一格式.- 该
double类型符合IEC 60559双格式.- 该
long double类型符合IEC 60559扩展格式,或非IEC 60559扩展格式,或IEC 60559double格式.
此外,它说正常算术必须遵循IEC 60559标准:
- 在
+,?,*,和/运营商提供了符合IEC 60559加,减,乘,除运算.
它还需要sqrt遵循IEC 60559:
- 这些
sqrt功能<math.h>提供IEC 60559平方根操作.
然后继续描述其他几个浮点函数的行为,其中大多数你可能对这个问题不感兴趣.
最后,它到达math.h包头,并指定如何使用各种数学函数(即sin,cos,atan2,exp,等)应处理特殊情况(即asin(±0)返回±0,atanh(x)返回为NaN并引发了"无效"的浮点异常的| X |> 1等).但它从来没有确定正常输入的精确计算,这意味着你不能依赖于产生完全相同计算的所有实现.
所以不,它不要求这些函数在所有实现中表现相同,即使所有实现都定义了__STDC_IEC_559__.
这都是从理论的角度来看的.在实践中,情况更糟.CPU通常实现IEC 60559算法,但是可以有不同的舍入模式(因此计算机的结果会有所不同),编译器(取决于优化标志)可能会做出一些不严格符合标准的假设.浮点运算.
所以在实践中,它甚至比理论上更严格,你很可能会看到两台计算机在某些时候产生的结果略有不同.
一个真实世界的例子是glibc,即GNU C库实现.它们有一个已知的错误限制表,用于跨不同CPU 的数学函数.如果所有C数学函数都是位精确的,那些表将显示0个错误的ULP.但他们没有.表格显示其C数学函数确实存在不同的误差量.我认为这句话是最有趣的总结:
除了某些函数,例如
sqrt,fma并且rint其结果通过参考相应的IEEE 754浮点运算完全指定,以及字符串和浮点之间的转换,GNU C库不针对数学库中函数的正确舍入结果[ ...]
glibc中唯一具有精确位置的东西是C标准的附件F要求精确的东西.正如你在他们的表中所看到的,大多数事情都没有.