简体   繁体   English

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

[英]c++ sqrt guaranteed precision, upper/lower bound

I have to check an inequality containing square roots. 我必须检查包含平方根的不等式。 To avoid incorrect results due to floating point inaccuracy and rounding, I use std::nextafter() to get an upper/lower bound: 为了避免由于浮点不准确和舍入导致的错误结果,我使用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) Is y*y >= x guaranteed using GCC compiler? a)使用GCC编译器是否保证y*y >= x

b) Will this work for other operations like + - * / or even std::cos() and std::acos() ? b)这适用于其他操作,如+ - * /甚至std::cos()std::acos()吗?

c) Are there better ways to get upper/lower bounds? c)是否有更好的方法来获得上限/下限?

Update: I read this is not guaranteed by the C++ Standard, but should work according to IEEE-754. 更新:我读过这不是C ++标准保证的,但应该按照IEEE-754工作。 Will this work with the GCC compiler? 这适用于GCC编译器吗?

In general, floating point operations will result in some ULP error. 通常,浮点运算将导致一些ULP错误。 IEEE 754 requires that results for most operations be correct to within 0.5 ULP, but errors can accumulate, which means a result may not be within one ULP of the the exact result. IEEE 754要求大多数操作的结果在0.5 ULP内正确,但错误可能累积,这意味着结果可能不在精确结果的一个ULP内。 There are limits to precision as well, so depending on the number of digits there are in resulting values, you also may not be working with values of the same magnitudes. 精度也有限制,因此根据结果值中的位数,您也可能无法使用相同大小的值。 Transcendental functions are also somewhat notorious for introducing error into calculations. 先验函数在将错误引入计算方面也有些臭名昭着

However, if you're using GNU glibc , sqrt will be correct to within 0.5 ULP (rounded), so you're specific example would work (neglecting NaN , +/-0 , +/-Inf ). 但是,如果您使用的是GNU glibc ,则sqrt将在0.5 ULP(舍入)范围内正确,因此您的具体示例将起作用(忽略NaN+/-0+/-Inf )。 Although, it's probably better to define some epsilon as your error tolerance and use that as your bound. 虽然,最好将一些epsilon定义为您的容错,并将其用作绑定。 For exmaple, 例如,

bool gt(double a, double b, double eps) {

  return (a > b - eps);
}

Depending on the level of precision you need in calculations, you also may want to use long double instead. 根据计算中所需的精度级别,您可能还需要使用long double

So, to answer your questions... 那么,回答你的问题......

a) Is y*y >= x guaranteed using GCC compiler? a)使用GCC编译器是否保证y * y> = x?

Assuming you use GNU glibc or SSE2 intrinsics, yes. 假设您使用GNU glibc或SSE2内在函数,是的。

b) Will this work for other operations like + - * / or even std::cos() and std::acos()? b)这适用于其他操作,如+ - * /甚至std :: cos()和std :: acos()吗?

Assuming you use GNU glibc and one operation, yes. 假设你使用GNU glibc和一个操作,是的。 Although some transcendentals are not guaranteed correctly rounded. 虽然一些超验主义并未得到正确的保证。

c) Are there better ways to get upper/lower bounds? c)是否有更好的方法来获得上限/下限?

You need to know what your error tolerance in calculations is, and use that as an epsilon (which may be larger than one ULP). 您需要知道计算中的误差容限,并将其用作epsilon(可能大于一个ULP)。

For GCC this page suggests that it will work if you use the GCC builtin sqrt function __builtin_sqrt . 对于GCC, 页面表明如果您使用GCC内置sqrt函数__builtin_sqrt ,它将起作用。

Additionally this behavior will be dependent on how you compile your code and the machine that it is run on 此外,此行为将取决于您编译代码的方式以及运行它的计算机

  1. If the processor supports SSE2 then you should compile your code with the flags -mfpmath=sse -msse2 to ensure that all floating point operations are done using the SSE registers. 如果处理器支持SSE2,那么您应该使用标志-mfpmath=sse -msse2编译代码,以确保使用SSE寄存器完成所有浮点操作。

  2. If the processor doesn't support SSE2 then you should use the long double type for the floating point values and compile with the flag -ffloat-store to force GCC to not use registers to store floating point values (you'll have a performance penalty for doing this) 如果处理器不支持SSE2,则应使用long double类型作为浮点值,并使用标志-ffloat-store进行编译,以强制GCC不使用寄存器来存储浮点值(您将受到性能损失)这样做)

Concerning 关于

c) Are there better ways to get upper/lower bounds? c)是否有更好的方法来获得上限/下限?

Another way is to use a different rounding mode , ie FE_UPWARD or FE_DOWNWARD instead of the default FE_TONEAREST . 另一种方法是使用不同的舍入模式 ,即FE_UPWARDFE_DOWNWARD而不是默认的FE_TONEAREST See https://stackoverflow.com/a/6867722 This may be slower , but is a better upper/lower bound. 请参阅https://stackoverflow.com/a/6867722这可能会更慢 ,但上限/下限更好。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM