fmod 関数を使用しようとしていますが、期待した結果が得られません。
3 に答える
浮動小数点の不正確さのため、実際には9.299999999999994を返します。55.8も9.3も、2を底とする浮動小数点数として正確に表すことはできません。
これは非常に一般的な問題です。良い参考資料の1つは、すべてのコンピューター科学者が浮動小数点演算について知っておくべきことです。
ほとんどの小数と同様に、これらの数値は 2 進浮動小数点値として正確に表すことはできません。の最も一般的な実装を想定するとdouble
、実際の値はおよそ次のようになります。
55.799999999999997158
と:
9.3000000000000007105
これらは正確には除算されず、結果fmod
はおおよそ次のようになります。
9.2999999999999936051
9.3
小数点以下の桁数が少ない場合は に丸められます。
これらの値は、次の C++ プログラムで生成されました。
#include <iostream>
#include <iomanip>
#include <cmath>
int main()
{
std::cout << std::setprecision(20);
double a = 55.8;
double b = 9.3;
std::cout << a << std::endl;
std::cout << b << std::endl;
std::cout << fmod(a,b) << std::endl;
}
6 に近いと予想しているという事実は、丸めを理解していないということではなく、fmod
実際に何をしているのかを知らないということを意味します。
fmod
商ではなく、割り算の余りです。つまり、除数の整数のコピーを差し引いた後の残りの量です。数学用語では、a = q*b + r
、 where q = int(a/b)
、およびr = fmod(a, b)
です。
a と b が正確に 55.8 と 9.3 の場合、a/b は正確に 6 になり、残りは 0 になります。したがって、結果として 0 を期待することは完全に合理的であり、一部のプラットフォームでは、実際に得られる結果になる可能性があります。
ただし、ほとんどのプラットフォームでは、55.8 および 9.3 に可能な最も近い近似値は約 55.799999999999997158 および 9.3000000000000007105 (理由については Mark Ransom の回答を参照) であり、商が 5.999999999999999 であることを意味します。 55.799999999999997158 - 9.3000000000000007105 * 5 = 9.299999999999997 で、9.3 と表示されます。
考えてみれば、これは理にかなっている。右の剰余が 0 の場合、小さな丸め誤差によって剰余が 1 または 6 になることはありません。実際に可能なのは、0 に非常に近いか、9.3 に非常に近いものだけです。(それが役立つ場合は、0 と 9.3 が同じ数であるモジュロ 9.3 算術について考えてみてください。)