double
は、テキストで表現できるすべての可能な数を表しているわけではありません。
double
は、典型的には、約2 の異なる数字を表すことができる。 double
がbinary floating point番号としてエンコードされている場合は、34000000.535
も33000000.535
も設定されていません。代わりに、最も近い表現可能な番号が使用されます。バイナリ浮動小数点数としてdouble
で
Text 34000000.535
closest double 34000000.534999996423...
Text 33000000.535
closest double 33000000.535000000149...
、100.0のように、非パワーの-2を乗じ、追加の丸め差異を導入することができます。しかし、これらのケースでは、依然としてxxx.5のすぐ上にある製品と、それよりも下にある製品が生成されます。
0.5
を追加すると、単純な2の累乗で、値が3x00000053.5に比べて極端ではないため、丸めの問題は発生しません。
中間結果を高い印刷精度に見れば、典型的なステップバイステップのプロセスがよく示されます。
#include <stdio.h>
#include <float.h>
#include <math.h>
void fma_test(double a, double b, double c) {
int n = DBL_DIG + 3;
printf("a b c %.*e %.*e %.*e\n", n, a, n, b, n, c);
printf("a*b %.*e\n", n, a*b);
printf("a*b+c %.*e\n", n, a*b+c);
printf("a*b+c %.*e\n", n, floor(a*b+c));
puts("");
}
int main(void) {
fma_test(34000000.535, 100, 0.5);
fma_test(33000000.535, 100, 0.5);
}
様々なプラットフォームが1)小数点浮動小数点double
を使用し、まれlong double
または2)のような高精度の数学を使用することができるように、出力
a b c 3.400000053499999642e+07 1.000000000000000000e+02 5.000000000000000000e-01
a*b 3.400000053499999523e+09
a*b+c 3.400000053999999523e+09
a*b+c 3.400000053000000000e+09
a b c 3.300000053500000015e+07 1.000000000000000000e+02 5.000000000000000000e-01
a*b 3.300000053500000000e+09
a*b+c 3.300000054000000000e+09
a*b+c 3.300000054000000000e+09
は、問題は、この簡単な答えより複雑です。したがって、コードの結果は異なる場合があります。 code that shows the representation of floats in memory as sum of termsを使用して
正確な計算が必要な場合は、丸めの問題はもちろん、任意精度の計算(たとえばgmp)のライブラリを使用してください。 – Ctx
あなたはバイナリ浮動小数点を扱っているからです。 – cHao
@cHao _decimal_ [浮動小数点](https://en.wikipedia.org/wiki/Decimal64_floating-point_format)でも、このような問題は、書式の精度限界に近い値で発生することに注意してください。これは浮動小数点演算のプロパティで、どのベースでも同じです。間違いなく10進数のテキストとバイナリの 'double'でよく使われます。 – chux