标准是否保证函数在所有实现中返回完全相同的结果?
以32位IEEE浮点数为例pow(float,float)
。如果传入相同的两个浮点数,则所有实现的结果是否相同?
或者,根据用于实现pow
的算法,标准允许哪些微小差异?
答案 0 :(得分: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扩展格式,否则为a 非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 |&gt; 1等的“无效”浮点异常。)。但它从来没有确定正常输入的精确计算,这意味着你不能依赖于产生精确相同计算的所有实现。
所以不,它不要求这些函数在所有实现中表现相同,即使实现都定义__STDC_IEC_559__
。
这完全是从理论的角度来看。在实践中,情况更糟。 CPU通常实现IEC 60559算法,但是可以有不同的舍入模式(因此结果会因计算机而异),编译器(取决于优化标志)可能会做出一些不严格符合标准的假设。浮点运算。
所以在实践中,它甚至比理论上更严格,你很可能会看到两台计算机在某些时候产生的结果略有不同。
一个真实世界的例子是glibc,即GNU C库实现。 They have a table of known error limits for their math functions跨越不同的CPU。如果所有C数学函数都是位精确的,那些表将显示0个错误的ULP。但他们没有。表格显示其C数学函数确实存在不同的误差量。我认为这句话是最有趣的总结:
除了某些函数,例如
sqrt
,fma
和rint
,其结果通过引用相应的IEEE 754浮点运算完全指定,以及字符串和浮点之间的转换, GNU C库的目标不是为数学库中的函数提供正确的舍入结果[...]
glibc中唯一具有位精确性的东西是C标准的附件F要求精确到位的东西。正如你在他们的表中所看到的,大多数事情都没有。