标准对 std::pow、std::log 等 cmath 函数有何规定?
What does standard say about cmath functions like std::pow, std::log etc?
标准是否保证函数 return 在所有实现中得到完全相同的结果?
例如 pow(float,float)
表示 32 位 IEEE 浮点数。如果传入相同的两个浮点数,所有实现的结果是否相同?
或者标准允许的一些灵活性取决于用于实现的算法的微小差异pow
?
不,C++ 标准不要求 cmath 函数的结果在所有实现中都相同。对于初学者,您可能无法获得 IEEE-754/IEC 60559 浮点运算。
也就是说,如果一个实现确实使用了 IEC 60559 并定义了 __STDC_IEC_559__
,那么它 必须 遵守 C 标准的附录 F(是的,你的问题是关于 C++,但 C++ 标准遵从 C header 的 C 标准,如 math.h
)。附件 F 指出:
- The
float
type matches the IEC 60559 single format.
- The
double
type matches the IEC 60559 double format.
- The
long double
type matches an IEC 60559 extended format, else a
non-IEC 60559 extended format, else the IEC 60559 double
format.
此外,它说正常运算必须遵循 IEC 60559 标准:
- The
+
, −
, *
, and /
operators provide the IEC 60559 add, subtract, multiply, and divide operations.
它进一步要求 sqrt
遵循 IEC 60559:
- The
sqrt
functions in <math.h>
provide the IEC 60559 square root operation.
然后继续描述其他几个 floating-point 函数的行为,对于这个问题,您可能对其中的大部分不感兴趣。
最后,它到达 math.h
header,并指定各种数学函数(即 sin
、cos
、atan2
、exp
, 等)应该处理特殊情况(即 asin(±0)
returns ±0
, atanh(x)
returns a NaN 并引发 "invalid" floating-point |x| > 1 等例外)。但它从未确定正常输入的确切计算,这意味着您不能依赖所有产生 精确 相同计算的实现。
所以不,它不需要这些函数在所有实现中表现相同,即使所有实现都定义了 __STDC_IEC_559__
.
这都是从理论上讲的。实际上,情况更糟。 CPU 通常执行 IEC 60559 算法,但可以有不同的舍入模式(因此结果会因计算机而异),并且编译器(取决于优化标志)可能会做出一些不严格符合您的标准的假设浮点运算。
因此在实践中,它甚至比理论上更不严格,您很可能会看到两台计算机在某些时候产生的结果略有不同。
一个真实世界的例子是 glibc,GNU C 库实现。 They have a table of known error limits for their math functions 跨不同的 CPU。如果所有 C 数学函数都是 bit-exact,那么那些 table 将全部显示 0 个错误 ULP。但他们没有。 tables 表明它们的 C 数学函数中确实存在不同数量的错误。我觉得这句话是最有意思的总结:
Except for certain functions such as sqrt
, fma
and rint
whose results are fully specified by reference to corresponding IEEE 754 floating-point operations, and conversions between strings and floating point, the GNU C Library does not aim for correctly rounded results for functions in the math library[...]
glibc 中唯一 bit-exact 的东西是 C 标准的附件 F 要求 bit-exact 的东西。正如您在他们的 table 中看到的那样,大多数情况并非如此。
标准是否保证函数 return 在所有实现中得到完全相同的结果?
例如 pow(float,float)
表示 32 位 IEEE 浮点数。如果传入相同的两个浮点数,所有实现的结果是否相同?
或者标准允许的一些灵活性取决于用于实现的算法的微小差异pow
?
不,C++ 标准不要求 cmath 函数的结果在所有实现中都相同。对于初学者,您可能无法获得 IEEE-754/IEC 60559 浮点运算。
也就是说,如果一个实现确实使用了 IEC 60559 并定义了 __STDC_IEC_559__
,那么它 必须 遵守 C 标准的附录 F(是的,你的问题是关于 C++,但 C++ 标准遵从 C header 的 C 标准,如 math.h
)。附件 F 指出:
- The
float
type matches the IEC 60559 single format.- The
double
type matches the IEC 60559 double format.- The
long double
type matches an IEC 60559 extended format, else a non-IEC 60559 extended format, else the IEC 60559double
format.
此外,它说正常运算必须遵循 IEC 60559 标准:
- The
+
,−
,*
, and/
operators provide the IEC 60559 add, subtract, multiply, and divide operations.
它进一步要求 sqrt
遵循 IEC 60559:
- The
sqrt
functions in<math.h>
provide the IEC 60559 square root operation.
然后继续描述其他几个 floating-point 函数的行为,对于这个问题,您可能对其中的大部分不感兴趣。
最后,它到达 math.h
header,并指定各种数学函数(即 sin
、cos
、atan2
、exp
, 等)应该处理特殊情况(即 asin(±0)
returns ±0
, atanh(x)
returns a NaN 并引发 "invalid" floating-point |x| > 1 等例外)。但它从未确定正常输入的确切计算,这意味着您不能依赖所有产生 精确 相同计算的实现。
所以不,它不需要这些函数在所有实现中表现相同,即使所有实现都定义了 __STDC_IEC_559__
.
这都是从理论上讲的。实际上,情况更糟。 CPU 通常执行 IEC 60559 算法,但可以有不同的舍入模式(因此结果会因计算机而异),并且编译器(取决于优化标志)可能会做出一些不严格符合您的标准的假设浮点运算。
因此在实践中,它甚至比理论上更不严格,您很可能会看到两台计算机在某些时候产生的结果略有不同。
一个真实世界的例子是 glibc,GNU C 库实现。 They have a table of known error limits for their math functions 跨不同的 CPU。如果所有 C 数学函数都是 bit-exact,那么那些 table 将全部显示 0 个错误 ULP。但他们没有。 tables 表明它们的 C 数学函数中确实存在不同数量的错误。我觉得这句话是最有意思的总结:
Except for certain functions such as
sqrt
,fma
andrint
whose results are fully specified by reference to corresponding IEEE 754 floating-point operations, and conversions between strings and floating point, the GNU C Library does not aim for correctly rounded results for functions in the math library[...]
glibc 中唯一 bit-exact 的东西是 C 标准的附件 F 要求 bit-exact 的东西。正如您在他们的 table 中看到的那样,大多数情况并非如此。