floatとdoubleの違いは何ですか?


420

倍精度と単精度の違いについて読みました。しかし、ほとんどの場合で、floatかつdouble交換可能であると思われる、すなわち、1つまたは他のを使用すると、結果に影響を与えていないようです。これは本当ですか?floatとdoubleはいつ交換可能ですか?それらの違いは何ですか?

回答:


521

大きな違い。

名前が示すように、a doubleの精度は[1]の 2倍です。一般に、a は15桁の精度を持ちますが、floatdoublefloatが、7。

桁数の計算方法は次のとおりです。

double52仮数ビット+ 1隠しビット:log(2 53)÷log(10)= 15.95桁

float23仮数ビット+ 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 ++標準はfloatdoubleおよびの表現を指定していませんlong double。3つすべてがIEEE倍精度として実装されている可能性があります。それにもかかわらず、ほとんどのアーキテクチャで(GCC、MSVC;のx86、x64の、ARM)がfloat あり、実際にIEEE単精度浮動小数点数(binary32)、及びdouble ある IEEE倍精度浮動小数点数(binary64)。


9
加算に関する通常のアドバイスは、加算する前に、浮動小数点数を絶対値で(最初に小さい)ソートすることです。
R .. GitHub ICE HELPING ICEの停止

C / C ++のfloatとdoubleはほとんど常にIEEEの単精度と倍精度ですが、C / C ++のlong doubleはCPU、コンパイラ、OSによってはるかに変動します。倍精度と同じ場合もあれば、システム固有の拡張形式の場合もあります。IEEE倍精度の場合もあります。
プラグウォッシュ

@ R..GitHubSTOPHELPINGICE:なぜですか?説明してもらえますか?
InQusitive

@InQusitive:たとえば、値2 ^ 24と、それに続く値1の2 ^ 24回の繰り返しで構成される配列を考えます。順番に合計すると、2 ^ 24が生成されます。反転すると2 ^ 25が生成されます。もちろん、例を作ることもできます(たとえば、1の2 ^ 25の繰り返しにする)と、任意の順序が単一のアキュムレータで壊滅的に間違ってしまいますが、その中で最小の大きさが最初です。より良いことをするためには、ある種の木が必要です。
R .. GitHub ICE HELPING ICE

56

標準のC99(ISO-IEC 9899 6.2.5§10)またはC ++ 2003(ISO-IEC 14882-2003 3.1.9§8)標準は次のように述べています。

そこ3つの浮動小数点タイプは、次のとおりですfloatdoublelong double。型doubleは少なくともと同じ精度を提供しfloat、型long doubleは少なくともと同じ精度を提供しdoubleます。タイプの値のセットは、タイプの値のセットのfloatサブセットdoubleです。タイプの値のセットは、タイプの値のセットのdoubleサブセットですlong double

C ++標準は以下を追加します。

浮動小数点型の値表現は実装定義です。

IEEE浮動小数点標準を詳細にカバーしている、浮動小数点演算についてすべてのコンピュータサイエンティストが知っておくべき優れたものをご覧になることをお勧めします。表現の詳細について学び、大きさと精度の間にトレードオフがあることに気づくでしょう。マグニチュードが減少するにつれて、浮動小数点表現の精度が高くなるため、-1から1までの浮動小数点数が最も精度の高い数値です。


27

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次方程式を解く最良の方法ではありませんが、より安定した方法を使用しても、答えは変わりません。)


19
  • doubleは64ビットで、単精度(float)は32ビットです。
  • doubleの仮数は大きくなります(実数の整数ビット)。
  • 誤差が2倍になると、誤差は小さくなります。

12

浮動小数点の計算に含まれる数値のサイズは、最も適切なものではありません。関連するのは、実行されている計算です。

本質的に、計算を実行していて、結果が無理数または繰り返し10進数である場合、その数が、使用している有限サイズのデータ​​構造に押しつぶされると、丸めエラーが発生します。doubleはfloatのサイズの2倍なので、丸め誤差はずっと小さくなります。

テストでは、特にこの種のエラーを引き起こす数値を使用する可能性があるため、コードで適切なタイプを使用したことをテストしました。


9

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を使用するだけで、多くの頭痛と型キャストを節約できます。


実際には、フロートの場合、正確には7〜8、7.225です。
Peter Mortensen

9

私はエラーに遭遇しただけで、それを理解するのに永遠にかかり、浮動小数点の精度の良い例を示す可能性があります。

#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時間かかりました。


4
念のため:問題の解決策は、できればintを使用することでしょうか?あなたが100回を反復処理したい場合は、むしろ、二重を使用するよりもint型でカウントすべきである
BlueTrin

8
ここでの使用doubleは良い解決策ではありません。を使用intして、浮動小数点値を取得するための内部乗算をカウントして実行します。
Richard


3

浮動小数点数を使用する場合、ローカルテストがサーバー側で実行されるテストとまったく同じになるとは信じられません。ローカルシステムと最終テストが実行される場所では、環境とコンパイラが異なる可能性があります。特に2つの浮動小数点数を比較しようとした場合、一部のTopCoderコンテストでこの問題を何度も目にしました。


3

組み込みの比較演算は、2つの数値を浮動小数点で比較する場合とは異なり、データ型(floatまたはdouble)の違いにより、結果が異なる場合があります。


1

エンベデッドプロセッシングで機能する場合、最終的にはハードウェア(FPGAまたは特定のプロセッサ/マイクロコントローラーモデルなど)がハードウェアに最適に実装されたフロートを持ち、ダブルはソフトウェアルーチンを使用します。したがって、フロートの精度がニーズを処理するのに十分である場合、プログラムはフロートよりも数倍速く実行され、次にダブルになります。他の回答で述べたように、累積エラーに注意してください。


-1

int(整数)とは異なり、a floatには小数点があり、aにも小数点がありdoubleます。ただし、2つの違いは、a doubleはの2倍の詳細floatであることです。つまり、小数点の後に2倍の数の数値を含めることができます。


4
それはまったくそういうことではありません。それは実際には2倍の数を意味します整数の 10進数の数を以上です。小数桁と精度の関係は線形ではありません。値によって異なります。たとえば、0.5は正確ですが、0.33333333333333333333はそうではありません。
ローン侯爵
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.