c ++ sqrt保证精度,上限/下限

时间:2015-08-25 15:25:09

标签: c++ c++11 floating-point floating-accuracy sqrt

我必须检查包含平方根的不等式。为了避免由于浮点不准确和舍入导致的错误结果,我使用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编译器一起使用吗?

3 个答案:

答案 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,它将起作用。

此外,此行为将取决于您编译代码的方式以及运行它的机器

  1. 如果处理器支持SSE2,那么您应该使用标志-mfpmath=sse -msse2编译代码,以确保使用SSE寄存器完成所有浮点操作。

  2. 如果处理器不支持SSE2,则应使用long double类型作为浮点值,并使用标志-ffloat-store进行编译,以强制GCC不使用寄存器来存储浮点数点值(这样做会对性能造成影响)

答案 2 :(得分:0)

关于

  

c)是否有更好的方法来获得上限/下限?

另一种方法是使用不同的rounding mode,即FE_UPWARDFE_DOWNWARD,而不是默认的FE_TONEAREST。请参阅https://stackoverflow.com/a/6867722这可能是slower,但是上限/下限更好。