5

私はコードを持っています

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 が大きすぎると、出力が小さいはずなのにオーバーフローしてしまいます。これを回避する方法はありますか?

4

2 に答える 2

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); 

これを最適化することはできますが、これは要点を示すためのものです。

于 2012-06-26T20:42:33.380 に答える
0

大きな x または y では、-1 は wrt (x*x)*(y*y) ... を無視できると思います。関数は long long を返すため、浮動小数点の精度は問題になりません。

x または y が大きいかどうかを確認できます。したがって、-1 を無視して、Chris または Rob の言うとおりにすることを選択できます。

于 2012-06-26T20:59:27.467 に答える