web-dev-qa-db-ja.com

倍精度-小数点以下の桁

私が読んだことから、データ型doubleの値は、小数点以下15桁の精度を持っています。ただし、1.0/7.0など、10進数表現が繰り返される数値を使用すると、変数が0.14285714285714285の値を保持していることがわかります。これは17桁です(デバッガー経由)。

内部で17桁で表されている理由と、15桁の精度が常に15桁で記述されている理由を知りたいのですが。

36
nf313743

IEEEのdoubleには53ビットの有効ビットがあります(これは_DBL_MANT_Dig_の_<cfloat>_の値です)。それは約15.95の10進数(log10(253));実装は、_DBL_Dig_を16ではなく15に設定します。これは、切り捨てる必要があるためです。そのため、(_DBL_Dig==15_によって暗示されるものを超えて)精度の余分な10進数の桁がほとんどあります。

nextafter()関数は、指定された数値に最も近い表現可能な数値を計算します。特定の数値がどれだけ正確かを示すために使用できます。

このプログラム:

_#include <cstdio>
#include <cfloat>
#include <cmath>

int main() {
    double x = 1.0/7.0;
    printf("FLT_RADIX = %d\n", FLT_RADIX);
    printf("DBL_Dig = %d\n", DBL_Dig);
    printf("DBL_MANT_Dig = %d\n", DBL_MANT_Dig);
    printf("%.17g\n%.17g\n%.17g\n", nextafter(x, 0.0), x, nextafter(x, 1.0));
}
_

私のシステムでこの出力を提供します:

_FLT_RADIX = 2
DBL_Dig = 15
DBL_MANT_Dig = 53
0.14285714285714282
0.14285714285714285
0.14285714285714288
_

(たとえば、_%.17g_を_%.64g_に置き換えると、重要な数字はありません。

ご覧のとおり、最後に表示された10進数は、連続する値ごとに3ずつ変化します。最後に表示された_1.0/7.0_(_5_)の桁が数学的な値と一致するという事実は、ほとんど偶然の一致です。それは幸運な推測でした。そして、正しい四捨五入桁は_6_ではなく_5_です。 _1.0/7.0_を_1.0/3.0_に置き換えると、次の出力が得られます。

_FLT_RADIX = 2
DBL_Dig = 15
DBL_MANT_Dig = 53
0.33333333333333326
0.33333333333333331
0.33333333333333337
_

予想どおり、約16桁の精度が表示されます。

35
Keith Thompson

これは実際には53桁の2進数であり、15の安定した小数点以下の桁数に変換されます。つまり、小数点以下15桁の数値で開始を丸めた場合、doubleに変換してからdouble小数点以下15桁に戻すと、同じ数字が得られます。 doubleを一意に表すには、小数点以下17桁が必要です(つまり、小数点以下17桁の数字ごとに、一意の最も近いdoubleがあることを意味します)。 -10進数は異なるdouble値にマッピングされます(他の回答の例のように)。

15
trutheality

浮動小数点数の10進表現は、ちょっと奇妙です。小数点以下15桁の数値があり、それをdoubleに変換し、小数点以下15桁だけで印刷すると、同じ数値が得られます。一方、小数点以下15桁の任意のdoubleを出力し、それをdoubleに戻す場合、必ずしも同じ値が返されるわけではありません。 17そのための小数点以下の桁数。また、任意のdoubleに相当する正確な10進数を正確に表示するには、小数点以下15桁でも17桁でも十分ではありません。通常、正確に行うには小数点以下100桁以上が必要です。

倍精度のWikipediaページ およびこの 浮動小数点の精度に関する記事 を参照してください。

12
John Calsbeek

Doubleは53桁の2進数を正確に保持します。これは10進数で〜15.9545898です。デバッガーは、binary値をより正確にするために、必要な数だけ数字を表示できます。または、fewer桁数と2進数(0.1など、10進数では1桁、2進数では無限)が必要になる場合があります。

これは奇妙なので、極端な例を示します。精度が2桁の3桁のみで、仮数または符号がない(範囲は0〜0.875)超シンプルな浮動小数点値を作成する場合、オプションは次のとおりです。

binary - decimal
000    - 0.000
001    - 0.125
010    - 0.250
011    - 0.375
100    - 0.500
101    - 0.625
110    - 0.750
111    - 0.875

ただし、数値を実行する場合、この形式は0.903089987の10進数まで正確です。 1桁でも正確ではありません。見やすいように、0.4??0.9??で始まる値はなく、完全な精度を表示するには、3桁の10進数が必要です。

tl; dr:デバッガーは浮動小数点変数の値を任意の精度(あなたの場合は19桁)で表示します)、これは必ずしも浮動小数点形式の精度(あなたの場合は17桁)とは相関しません。

7
Mooing Duck

IEEE 754浮動小数点はバイナリで実行されます。特定のビット数から特定の数の10進数への正確な変換はありません。 3ビットは0〜7の値を保持でき、4ビットは0〜15の値を保持できます。0〜9の値は大まかに 3.5ビットを取りますが、これも正確ではありません。

IEEE 754倍精度数は64ビットを占有します。このうち、52ビットは仮数専用です(残りは符号ビットと指数です)。仮数部は(通常)正規化されているため、暗黙の53rd ビット。

現在、53ビットと1桁あたり約3.5ビットの単純な除算により、15.1429桁の精度が得られます。ただし、1桁あたり3.5ビットは近似値にすぎず、完全に正確な答えではないことに注意してください。

多くの(ほとんど?)デバッガーは、実際にレジスタ全体の内容を調べます。 x86では、実際には80ビットの数値です。 x86浮動小数点ユニットは通常、64ビット精度で計算を実行するように調整されますが、内部では、実際には2、3の「ガードビット」を使用します。最後のものを正しく丸めることができます。デバッガーがレジスター全体を見ると、通常はかなり正確な追加の桁が少なくとも1つ見つかりますが、その桁にはガードビットがないため、正しく丸められない場合があります。

4
Jerry Coffin

バイナリ表現から変換されているためです。それらの10進数をすべて出力したからといって、その精度ですべての10進数値を表現できるわけではありません。たとえば、Pythonの場合:

>>> 0.14285714285714285
0.14285714285714285
>>> 0.14285714285714286
0.14285714285714285

最後の数字をどのように変更したかに注意してください。しかし、とにかく同じ数字が出力されました。

3
spencercw

double値が使用されるほとんどのコンテキストでは、計算にはある程度の不確実性があります。 1.33333333333333300と1.33333333333333399の差は、計算に存在する不確実性の量よりも小さい場合があります。 「2/3 + 2/3」の値を「1.33333333333333」として表示する方が、「1.33333333333333319」として表示するよりも意味があります。後者の表示は、実際には存在しないレベルの精度を意味するためです。

ただし、デバッガーでは、変数が保持する値を一意に示すことが重要です。 本質的に意味のない精度のビットを含む。デバッガーが2つの変数に値「1.333333333333333」を保持していると表示し、一方が実際に1.33333333333333319を保持し、もう一方が1.33333333333333294を保持している場合(同じように見えても、等しくないことを意味します)、非常に混乱します。デバッガーによって表示される余分な精度は、数値的に正しい計算結果を表す傾向はありませんが、変数が保持する値をコードがどのように解釈するかを示します。

1
supercat