@tmyklebu は質問に完全に答えました。補足として、asm ディレクティブを使用せずに分数の完全な 2 乗をテストするための、おそらく効率の悪い代替手段を見てみましょう。
結果を正しく丸める IEEE 754 準拠の sqrt があるとします。
例外的な値 (Inf/Nan) とゼロ (+/-) が既に処理されているとします。が奇数である場所に分解し
ましょう。
そして、n ビットにまたがる場所: .sqrt(x)
I*2^m
I
I
1+2^(n-1) <= I < 2^n
n > 1+floor(p/2)
whereが浮動小数点精度の場合p
(例: 倍精度で p=53 および n>27)
Then 2^(2n-2) < I^2 < 2^2n
. 奇数である
ため、奇数でもあり、したがって > p ビットにまたがります。
したがって、この精度で表現可能な浮動小数点の正確な平方根ではありません。I
I^2
I
しかし、 が与えられた場合、それは完全な正方形であるI^2<2^p
と言えますか?
答えは明らかにノーです。テイラー展開はx
sqrt(I^2+e)=I*(1+e/2I - e^2/4I^2 + O(e^3/I^3))
したがって、平方根までは ... に正しく丸められe=ulp(I^2)
ます(最も近い偶数に丸める、切り捨てる、またはフロア モード)。sqrt(ulp(I^2))
rsqrt(I^2+e)=I
したがって、それを主張する必要がありsqrt(x)*sqrt(x) == x
ます。
But above test is not sufficient, for example, assuming IEEE 754 double precision, sqrt(1.0e200)*sqrt(1.0e200)=1.0e200
, where 1.0e200 is exactly 99999999999999996973312221251036165947450327545502362648241750950346848435554075534196338404706251868027512415973882408182135734368278484639385041047239877871023591066789981811181813306167128854888448 whose first prime factor is 2^613
, hardly a perfect square of any fraction...
したがって、両方のテストを組み合わせることができます。
#include <float.h>
bool is_perfect_square(double x) {
return sqrt(x)*sqrt(x) == x
&& squared_significand_fits_in_precision(sqrt(x));
}
bool squared_significand_fits_in_precision(double x) {
double scaled=scalb( x , DBL_MANT_DIG/2-ilogb(x));
return scaled == floor(scaled)
&& (scalb(scaled,-1)==floor(scalb(scaled,-1)) /* scaled is even */
|| scaled < scalb( sqrt((double) FLT_RADIX) , DBL_MANT_DIG/2 + 1));
}
編集:
整数の場合に制限したい場合は、それを確認するfloor(sqrt(x))==sqrt(x)
か、squared_significand_fits_in_precision でダーティ ビット ハックを使用することもできます...