経験的に、答えは何ではありません。 4503599761588224の入力の結果は、67108864ではなく67108865と誤って計算されます。
次のコードは、このケースを識別しています。 もちろん、break;
を削除して他のケースを観察することもできます。
#include <stdio.h>
#include <stdint.h>
#include <math.h>
int main(void) {
for (uint32_t y = 1; y != 0; y++) {
// *Just* smaller than a perfect square
uint64_t x = ((uint64_t)y * (uint64_t)y) - 1;
// We expect the floor of the result
uint32_t expected = y - 1;
uint32_t result = (uint32_t)sqrt((double)x);
if (result != expected) {
printf("Incorrect: x = %llu, result = %u\n", x, result);
break;
}
}
return 0;
}
値4503599761588224の特長は何ですか?まあ、それはまさに(2 +1) - 1、AKA(2 + 2 )です。これは正確にdouble
で表すことができるので、エラーはlong
- >double
の変換によるものではありません。
代わりに、エラーはsqrt
実装の内部にあります。ここでのデルタ(完全な正方形に対する)は、平方根を約2×-27だけ減少させ、それは約2 倍であり、それ自体result
より小さい。これは、倍精度で扱うことができる限界にあります。この時点では、当然、オフ・バイ・ワンのエラーが発生することが予想されます。
1. Live demo。あなたは数学ライブラリの `sqrt`が良いですし、あなたのCを知っている場合でも、` uint32_t`ため:)
下のコメントで根本的な原因を特定するための@EricPostpischilへ
2.クレジットは、これが唯一の信頼性があります浮動小数点演算では実装が良好です。 C標準だけではこれは必要ありません。数学ライブラリの中には、正確な平方根を表現できる値であっても、おおよその結果しか返さないものがあります。 –
私は32ビット整数の二重戦略を推薦しましたが、それはJavaの質問に応答していました。[回答](https://stackoverflow.com/a/15212684/1798593)答えはJava固有の保証に依存しており、Cには適用されません。 –