如何防止sqrt溢出?

时间:2012-06-26 20:37:37

标签: c++ math sqrt

我有代码

unsigned long long f(unsigned long long x, unsigned long long y){
   return sqrt( ( (5*x*x + 1) * (5*y*y +1) - 1 ) / 4 );         
}

但是如果x或y太大,即使输出应该很小,东西也会溢出。有没有解决的办法?

2 个答案:

答案 0 :(得分:8)

用代数方式将平方根的参数分开,可能吗?:

return sqrt((3*x*x+1)/2) * sqrt((6*y*y-5)/2);

或根据您的需要进一步分割。

如果x足够大,您可以忽略+1并制作第一个词:

sqrt((3*x*x)/2) = fabs(x) * sqrt(3.0/2.0)

与第二学期的y类似,使其成为

sqrt((6*y*y)/2) = fabs(y) * sqrt(3.0);

编辑:在OP编辑他的问题后:

return sqrt(((3*x*x+1)*(6*y*y-5)-1)/4);  

事实上你可以分手了。你必须要小心一些。最重要的是,如果x非常大,那么可以忽略+1。如果y非常大,则可以忽略-5。如果(3*x*x+1)(6*y*y-5)都是正数且其中任何一个都很大,则可以忽略-1。您可以使用这些提示和一些额外的周围逻辑来进一步分解这一点。像这样:

 if(fabs(x) > BIGNUMBER && fabs(y) > BIGNUMBER)
 {
     return fabs(x) * fabs(y) * sqrt(18.0/4.0);
 }
 if(fabs(x) > BIGNUMBER && fabs(y) > 1.0)  // x big and y term positive
 {
     return fabs(x) * sqrt(6*y*y-5) * sqrt(3.0/2.0);
 }
 if(fabs(y) > BIGNUMBER)  // x term positive and y big
 {
     return sqrt(3*x*x+1) * fabs(y) * sqrt(6.0/2.0);
 }
 return sqrt(((3*x*x+1)*(6*y*y-5)-1)/4); 

你可以对此进行优化,但这只是为了表明这一点。

答案 1 :(得分:0)

我相信在大的x或y,-1可以忽略wrt(x * x)*(y * y)...并且由于你的函数返回long long,浮点精度无关紧要。

你可以检查x或y是否大,因此,你可以选择忽略-1并按照Chris或Rob的说法进行操作。