私はコードを持っています
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 が大きすぎると、出力が小さいはずなのにオーバーフローしてしまいます。これを回避する方法はありますか?
平方根の引数を代数的に分割しますか?:
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);
これを最適化することはできますが、これは要点を示すためのものです。
大きな x または y では、-1 は wrt (x*x)*(y*y) ... を無視できると思います。関数は long long を返すため、浮動小数点の精度は問題になりません。
x または y が大きいかどうかを確認できます。したがって、-1 を無視して、Chris または Rob の言うとおりにすることを選択できます。