标准对std::pow、std::log等cmath函数有什么规定?
What does standard say about cmath functions like std::pow, std::log etc?
标准是否保证函数在所有实现中返回完全相同的结果?
以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 60559double
格式。
进一步,它说正常的算术必须遵循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
,fma
和rint
等函数的结果完全由相应的IEEE 754浮点操作和字符串与浮点之间的转换来指定外,GNU C库不以数学库中的函数的正确四舍五入结果为目标[…]
glibc中唯一精确的东西是C标准附录F中要求精确的东西。正如你在他们的表格中看到的,大多数东西都不是。
- 这个语法std::class<>{}(arg1, arg2) 在C++中是什么意思?
- "using namespace std;"在C++的作用是什么?
- 传递给std::function template的template参数究竟代表什么
- "std::unique_XXX"命名约定背后的基本原理是什么?
- 什么是 std::exception::what() 以及为什么要使用它?
- C++如果必须在编译时确定大小,std::array 有什么意义?
- 当我们进行一些操作时,应该使用什么'std::string'或'std::stringstream'?
- 如果 KEY 是 std::list 或 std::vector 而不是值,那么 std::map 的默认行为是什么?
- 当 std::move 与 C 样式数组或不移动对象时会发生什么
- 什么是自动 t1=std::make_tuple(case1==case2,整数)的值
- C++std::atomic在程序员级别保证了什么
- 当为可变性配置时,boost::heap::d_ary_heap 保留的额外 std::list 的目的是什么?
- 引用 std::any 或 not_yet_in_std::whatever 的惯用方式是什么?
- 在什么条件下使用 std::memcpy 在对象之间复制是安全的?
- 在自定义 std::vector-like 容器中处理指针和非指针模板类型的最佳方法是什么?
- 在 C# 中等效的 std::rotate() 是什么?
- 什么是 std::function::argument_type 的替代品?
- 什么是 std::jthread 在 c++20 中?
- std::enable_if 和 std::enable_if_t 有什么区别?
- "owned pointer"和 std::shared_ptr 的"stored pointer"有什么区别?