我必须检查包含平方根的不等式。为了避免由于浮点不准确和舍入导致的错误结果,我使用std::nextafter()
来获得上限/下限:
#include <cfloat> // DBL_MAX
#include <cmath> // std::nextafter, std::sqrt
double x = 42.0; //just an example number
double y = std::nextafter(std::sqrt(x), DBL_MAX);
a)使用GCC编译器保证y*y >= x
吗?
b)这适用于+ - * /
甚至std::cos()
和std::acos()
等其他操作吗?
c)是否有更好的方法来获得上限/下限?
更新: I read这不是C ++标准保证的,但应该符合IEEE-754标准。这可以与GCC编译器一起使用吗?
答案 0 :(得分:3)
通常,浮点运算会导致一些ULP错误。 IEEE 754要求大多数操作的结果在0.5 ULP内正确,但错误可能累积,这意味着结果可能不在精确结果的一个ULP内。精度也有限制,因此根据结果值中的位数,您也可能无法使用相同大小的值。对于将误差引入计算,超越函数也有些notorious。
但是,如果您使用GNU glibc,则sqrt将在0.5 ULP(舍入)范围内正确,因此您的具体示例将起作用(忽略NaN
,{ {1}},+/-0
)。虽然,将某些epsilon定义为您的容错并将其用作绑定可能更好。例如,
+/-Inf
根据计算中所需的精确程度,您可能还想使用bool gt(double a, double b, double eps) {
return (a > b - eps);
}
。
所以,回答你的问题......
a)使用GCC编译器保证y * y&gt; = x吗?
假设您使用GNU glibc或SSE2内在函数,是的。
b)这是否适用于其他操作,如+ - * /甚至std :: cos()和std :: acos()?
假设您使用GNU glibc和一个操作,是的。虽然一些超验主义并未得到正确的保证。
c)是否有更好的方法来获得上限/下限?
您需要知道计算中的误差容限,并将其用作epsilon(可能大于一个ULP)。
答案 1 :(得分:2)
对于GCC this页面建议,如果您使用GCC内置sqrt函数__builtin_sqrt
,它将起作用。
此外,此行为将取决于您编译代码的方式以及运行它的机器
如果处理器支持SSE2,那么您应该使用标志-mfpmath=sse -msse2
编译代码,以确保使用SSE寄存器完成所有浮点操作。
如果处理器不支持SSE2,则应使用long double
类型作为浮点值,并使用标志-ffloat-store
进行编译,以强制GCC不使用寄存器来存储浮点数点值(这样做会对性能造成影响)
答案 2 :(得分:0)
关于
c)是否有更好的方法来获得上限/下限?
另一种方法是使用不同的rounding mode,即FE_UPWARD
或FE_DOWNWARD
,而不是默认的FE_TONEAREST
。请参阅https://stackoverflow.com/a/6867722这可能是slower,但是上限/下限更好。