标准对std::pow、std::log等cmath函数有什么规定?

What does standard say about cmath functions like std::pow, std::log etc?

本文关键字:std 什么 函数 pow log 标准 cmath      更新时间:2023-10-16

标准是否保证函数在所有实现中返回完全相同的结果?

以32位IEEE浮点数pow(float,float)为例。如果传递相同的两个浮点数,所有实现的结果都相同吗?

标准是否允许根据实现pow所使用的算法的微小差异而具有一些灵活性?

不,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 60559 double格式。

进一步,它说正常的算术必须遵循IEC 60559标准:

  • +*/运算符提供IEC 60559的加、减、乘、除运算。

它进一步要求sqrt遵循IEC 60559:

  • <math.h>中的sqrt函数提供IEC 60559的平方根运算。

接着描述了其他几个浮点函数的行为,其中大多数你可能对这个问题不感兴趣。

最后,它到达math.h头,并指定各种数学函数(即sin, cos, atan2, exp等)应该如何处理特殊情况(即asin(±0)返回±0, atanh(x)返回NaN并引发"无效"浮点异常|x|> 1等)。但是它从来没有确定正常输入的精确计算,这意味着你不能依赖于所有的实现产生精确的相同的计算。

所以不,它不要求这些函数在所有实现中表现相同,即使实现都定义了__STDC_IEC_559__


这些都是从理论角度出发的。实际上,情况甚至更糟。cpu通常实现IEC 60559算法,但它可以有不同的舍入模式(因此结果会因计算机而异),并且编译器(取决于优化标志)可能会做出一些假设,这些假设并不严格符合您的浮点算法的标准。

所以在实践中,它甚至没有理论上那么严格,你很可能会看到两台计算机在某个时候产生稍微不同的结果。


一个真实的例子是GNU C库实现glibc。他们有一个表,列出了不同cpu上数学函数的已知错误限制。如果所有C数学函数都是位精确的,那么这些表都将显示0错误ulp。但他们没有。这些表格显示,他们的C数学函数中确实存在不同数量的错误。我认为这句话是最有趣的总结:

除了sqrt, fmarint等函数的结果完全由相应的IEEE 754浮点操作和字符串与浮点之间的转换来指定外,GNU C库不以数学库中的函数的正确四舍五入结果为目标[…]

glibc中唯一精确的东西是C标准附录F中要求精确的东西。正如你在他们的表格中看到的,大多数东西都不是。