倍精度と単精度の違いについて読みました。しかし、ほとんどの場合で、float
かつdouble
交換可能であると思われる、すなわち、1つまたは他のを使用すると、結果に影響を与えていないようです。これは本当ですか?floatとdoubleはいつ交換可能ですか?それらの違いは何ですか?
倍精度と単精度の違いについて読みました。しかし、ほとんどの場合で、float
かつdouble
交換可能であると思われる、すなわち、1つまたは他のを使用すると、結果に影響を与えていないようです。これは本当ですか?floatとdoubleはいつ交換可能ですか?それらの違いは何ですか?
回答:
大きな違い。
名前が示すように、a double
の精度は[1]の 2倍です。一般に、a は15桁の精度を持ちますが、float
double
float
が、7。
桁数の計算方法は次のとおりです。
double
52仮数ビット+ 1隠しビット:log(2 53)÷log(10)= 15.95桁
float
23仮数ビット+ 1隠しビット:log(2 24)÷log(10)= 7.22桁
この精度の低下により、繰り返し計算が行われると、たとえば次のような大きな切り捨てエラーが蓄積される可能性があります。
float a = 1.f / 81;
float b = 0;
for (int i = 0; i < 729; ++ i)
b += a;
printf("%.7g\n", b); // prints 9.000023
ながら
double a = 1.0 / 81;
double b = 0;
for (int i = 0; i < 729; ++ i)
b += a;
printf("%.15g\n", b); // prints 8.99999999999996
また、floatの最大値は約3e38
ですが、doubleは約1.7e308
であるため、使用float
するとdouble
、たとえば60の階乗の計算など、単純なものよりもはるかに簡単に「無限大」(つまり、特別な浮動小数点数)にヒットできます。
テスト中、おそらくいくつかのテストケースにこれらの膨大な数が含まれているため、フロートを使用するとプログラムが失敗する可能性があります。
もちろん、場合によってdouble
は、十分に正確ではないこともあるため、long double
[1]になることもあります(上記の例ではMacでは9.000000000000000066になります)が、すべての浮動小数点型で丸めエラーが発生するため、精度が非常に重要な場合(お金など)処理)int
または分数クラスを使用する必要があります。
さらに、+=
エラーがすぐに累積するため、大量の浮動小数点数を合計するために使用しないでください。Pythonを使用している場合は、を使用しますfsum
。それ以外の場合は、Kahan加算アルゴリズムを実装してみてください。
[1]:CおよびC ++標準はfloat
、double
およびの表現を指定していませんlong double
。3つすべてがIEEE倍精度として実装されている可能性があります。それにもかかわらず、ほとんどのアーキテクチャで(GCC、MSVC;のx86、x64の、ARM)がfloat
あり、実際にIEEE単精度浮動小数点数(binary32)、及びdouble
ある IEEE倍精度浮動小数点数(binary64)。
標準のC99(ISO-IEC 9899 6.2.5§10)またはC ++ 2003(ISO-IEC 14882-2003 3.1.9§8)標準は次のように述べています。
そこ3つの浮動小数点タイプは、次のとおりです
float
、double
とlong double
。型double
は少なくともと同じ精度を提供しfloat
、型long double
は少なくともと同じ精度を提供しdouble
ます。タイプの値のセットは、タイプの値のセットのfloat
サブセットdouble
です。タイプの値のセットは、タイプの値のセットのdouble
サブセットですlong double
。
C ++標準は以下を追加します。
浮動小数点型の値表現は実装定義です。
IEEE浮動小数点標準を詳細にカバーしている、浮動小数点演算についてすべてのコンピュータサイエンティストが知っておくべき優れたものをご覧になることをお勧めします。表現の詳細について学び、大きさと精度の間にトレードオフがあることに気づくでしょう。マグニチュードが減少するにつれて、浮動小数点表現の精度が高くなるため、-1から1までの浮動小数点数が最も精度の高い数値です。
x 2 − 4.0000000 x + 3.9999999 = 0の2次方程式が与えられた場合、10桁の有効数字の正確な根は、r 1 = 2.000316228およびr 2 = 1.999683772です。
float
およびを使用してdouble
、テストプログラムを作成できます。
#include <stdio.h>
#include <math.h>
void dbl_solve(double a, double b, double c)
{
double d = b*b - 4.0*a*c;
double sd = sqrt(d);
double r1 = (-b + sd) / (2.0*a);
double r2 = (-b - sd) / (2.0*a);
printf("%.5f\t%.5f\n", r1, r2);
}
void flt_solve(float a, float b, float c)
{
float d = b*b - 4.0f*a*c;
float sd = sqrtf(d);
float r1 = (-b + sd) / (2.0f*a);
float r2 = (-b - sd) / (2.0f*a);
printf("%.5f\t%.5f\n", r1, r2);
}
int main(void)
{
float fa = 1.0f;
float fb = -4.0000000f;
float fc = 3.9999999f;
double da = 1.0;
double db = -4.0000000;
double dc = 3.9999999;
flt_solve(fa, fb, fc);
dbl_solve(da, db, dc);
return 0;
}
プログラムを実行すると、次のようになります。
2.00000 2.00000
2.00032 1.99968
数値は大きくありませんが、それでもを使用してキャンセル効果を得ることに注意してくださいfloat
。
(実際、上記は単精度または倍精度の浮動小数点数を使用して2次方程式を解く最良の方法ではありませんが、より安定した方法を使用しても、答えは変わりません。)
float型、長さ32ビット、精度は7桁です。非常に大きい範囲または非常に小さい範囲(+/- 3.4 * 10 ^ 38または* 10 ^ -38)の値を格納できますが、有効数字は7桁のみです。
タイプdouble、64ビット長、より大きな範囲(* 10 ^ + /-308)および15桁の精度。
タイプlong doubleは名目上80ビットですが、コンパイラとOSの組み合わせによっては、アライメントのために12〜16バイトとして格納される場合があります。長いdoubleの指数は途方もなく巨大で、19桁の精度でなければなりません。マイクロソフトは、その無限の知恵により、プレーンダブルと同じように、ロングダブルを8バイトに制限しています。
一般的に、浮動小数点値/変数が必要な場合は、double型を使用してください。式で使用されるリテラル浮動小数点値はデフォルトでdoubleとして扱われ、浮動小数点値を返すほとんどの数学関数はdoubleを返します。doubleを使用するだけで、多くの頭痛と型キャストを節約できます。
私はエラーに遭遇しただけで、それを理解するのに永遠にかかり、浮動小数点の精度の良い例を示す可能性があります。
#include <iostream>
#include <iomanip>
int main(){
for(float t=0;t<1;t+=0.01){
std::cout << std::fixed << std::setprecision(6) << t << std::endl;
}
}
出力は
0.000000
0.010000
0.020000
0.030000
0.040000
0.050000
0.060000
0.070000
0.080000
0.090000
0.100000
0.110000
0.120000
0.130000
0.140000
0.150000
0.160000
0.170000
0.180000
0.190000
0.200000
0.210000
0.220000
0.230000
0.240000
0.250000
0.260000
0.270000
0.280000
0.290000
0.300000
0.310000
0.320000
0.330000
0.340000
0.350000
0.360000
0.370000
0.380000
0.390000
0.400000
0.410000
0.420000
0.430000
0.440000
0.450000
0.460000
0.470000
0.480000
0.490000
0.500000
0.510000
0.520000
0.530000
0.540000
0.550000
0.560000
0.570000
0.580000
0.590000
0.600000
0.610000
0.620000
0.630000
0.640000
0.650000
0.660000
0.670000
0.680000
0.690000
0.700000
0.710000
0.720000
0.730000
0.740000
0.750000
0.760000
0.770000
0.780000
0.790000
0.800000
0.810000
0.820000
0.830000
0.839999
0.849999
0.859999
0.869999
0.879999
0.889999
0.899999
0.909999
0.919999
0.929999
0.939999
0.949999
0.959999
0.969999
0.979999
0.989999
0.999999
0.83以降でわかるように、精度は大幅に低下します。
しかし、私が設定した場合 t
二重と、このような問題は発生しません。
私のプログラムを台無しにしたこの小さなエラーに気付くのに5時間かかりました。
double
は良い解決策ではありません。を使用int
して、浮動小数点値を取得するための内部乗算をカウントして実行します。
floatはdoubleよりも精度が低くなります。すでにご存じでしょうが、理解を深めるには、浮動小数点演算について知っておくべきことをお読みください。
浮動小数点数を使用する場合、ローカルテストがサーバー側で実行されるテストとまったく同じになるとは信じられません。ローカルシステムと最終テストが実行される場所では、環境とコンパイラが異なる可能性があります。特に2つの浮動小数点数を比較しようとした場合、一部のTopCoderコンテストでこの問題を何度も目にしました。