coutを使用して完全な精度でdouble値を印刷するにはどうすればよいですか?


回答:


391

精度を直接設定してstd::coutstd::fixedフォーマット指定子を使用できます。

double d = 3.14159265358979;
cout.precision(17);
cout << "Pi: " << fixed << d << endl;

#include <limits>floatまたはdoubleの最大精度を取得できます。

#include <limits>

typedef std::numeric_limits< double > dbl;

double d = 3.14159265358979;
cout.precision(dbl::max_digits10);
cout << "Pi: " << d << endl;

46
使用することを明示的に勧めるのはなぜfixedですか?でdouble h = 6.62606957e-34;fixed0.000000000000000scientific出力を提供します6.626069570000000e-34
Arthur

36
精度は17(またはstd :: numeric_limits <double> :: digits10 + 2)である必要があります。これは、10進数からバイナリ表現に変換して値を元の値に丸めるために2桁余分に必要になるためです。これがいくつかの詳細を含む論文です:docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html
マイクフィッシャー

8
本当に正しい答えですか?私は手動で高い数値を使用する場合、Iは近似Eの51桁の数だけ印刷することができるが、とcout.precision(numeric_limits<double>::digits10 + 2);私は16を得る....
Assimilater

6
それは引用@MikeFisher紙に17桁の数字に言及している場所をお探しの方のために、それは定理15の下だ
エミール・コーミア

15
@MikeFisherそうですね、C ++ 11max_digits10は同じことを示すために導入しています。これを反映するように答えを修正しました。
legends2k

70

使用std::setprecision

std::cout << std::setprecision (15) << 3.14159265358979 << std::endl;

2
MAX_PRECISIONマクロや列挙型など、std :: setPrecisionに渡すことができるものはありますか?
Jason Punyon

2
std :: setprecision(15)(double(okまたは16)の場合)、log_10(2 ** 53)〜= 15.9
user7116

14
std ::てSetPrecision(<ダブル>のstd :: numeric_limitsの:: digits10)
エリックMalenfant

6
std::setprecision (17)二重にする必要があります。@ Bill The Lizardの回答のコメントを参照してください。
Alec Jacobson、2015

9
std :: setprecisionを機能させるには、#include <iomanip>を含める必要があります。
user2262504 2016

24

これが私が使うものです:

std::cout << std::setprecision (std::numeric_limits<double>::digits10 + 1)
          << 3.14159265358979
          << std::endl;

基本的に、limitsパッケージには、すべての組み込みタイプの特性があります。
浮動小数点数(float / double / long double)の特性の1つは、digits10属性です。これは、10を底とする浮動小数点数の正確さ(正確な用語を忘れています)を定義します。

他の属性の詳細については、http//www.cplusplus.com/reference/std/limits/numeric_limits.htmlを参照してください


12
このヘッダは、使用に必要とされているstd::setprecision()#include <iomanip>
マーティン・ベルガー

それはする必要がありますstd::numeric_limits<double>代わりにnumberic_limits<double>
niklasfi

2
なぜ追加1するのstd::numeric_limits<double>::digits10ですか?
アレッサンドロジャコプソン2014年

5
@LokiAstari max_digits10代わりにC + 11を使用できます。参照してくださいこれを
legends2k

1
@AlecJacobson恣意的ではなくmax_digits10、むしろそうすべきdigits10+2です。それ以外の場合は、の場合にはfloatlong doubleboost::multiprecision::float128あなたがそこに必要があると思いますので、これは、失敗します+3代わりに+2
ルスラン

14

iostreamの方法はちょっと不格好です。boost::lexical_cast正しい精度が計算されるので、使用することを好みます。そして、それ速いです。

#include <string>
#include <boost/lexical_cast.hpp>

using boost::lexical_cast;
using std::string;

double d = 3.14159265358979;
cout << "Pi: " << lexical_cast<string>(d) << endl;

出力:

Pi:3.14159265358979


ブーストのドキュメントには、「std :: numeric_limitsの対応する特殊化を持つ数値の場合、現在のバージョンは一致する精度を選択するようになりました」とあります。これは、最大精度を得る最も簡単な方法のようです。(boost.org/doc/libs/1_58_0/doc/html/boost_lexical_cast/...
JDiMatteo

11

完全な精度とは、意図した値に最も近い近似を示すのに十分な精度を意味しますが、doublebase 2表現を使用して格納され、base 2はそれほど単純なものを表現できないことを指摘する必要があります1.1。実際のdoubleの完全な精度を取得する唯一の方法(NO ROUND OFF ERRORを使用)は、バイナリビット(または16進ニブル)を出力することです。これを行う1つの方法は、doubleをaに書き込みunion、ビットの整数値を出力することです。

union {
    double d;
    uint64_t u64;
} x;
x.d = 1.1;
std::cout << std::hex << x.u64;

これにより、倍精度の100%正確な精度が得られます。人間はIEEE倍精度形式を読み取ることができないため、まったく判読できません。 ウィキペディアには、バイナリビットの解釈方法に関する優れた記事があります。

新しいC ++では、次のことができます

std::cout << std::hexfloat << 1.1;

10

以下は、完全精度でdoubleを表示する方法です。

double d = 100.0000000000005;
int precision = std::numeric_limits<double>::max_digits10;
std::cout << std::setprecision(precision) << d << std::endl;

これは表示します:

100.0000000000005


max_digits10は、すべての個別のdouble値を一意に表すために必要な桁数です。max_digits10は、小数点の前後の桁数を表します。


std :: fixedでset_precision(max_digits10)を使用しないでください。
固定表記上、set_precision()は、桁数を設定した後にのみ小数点。max_digits10は、桁数を表し、これは間違っているの前後に小数点。

double d = 100.0000000000005;
int precision = std::numeric_limits<double>::max_digits10;
std::cout << std::fixed << std::setprecision(precision) << d << std::endl;

これは間違った結果を表示します:

100.00000000000049738

注:必要なヘッダーファイル

#include <iomanip>
#include <limits>

4
これは、100.0000000000005がとして正確に表されていないために発生しdoubleます。(正常に見えるように見えるかもしれませんが、正規化されるため、そうではありません。つまり、バイナリ表現です)。これを確認するには、次を試してください100.0000000000005 - 100。我々が得ます4.973799150320701e-13
Evgeni Sergeev 2017

9

doublecoutを使用して完全な精度で値を印刷するにはどうすればよいですか?

精度を使用hexfloatまたは
使用scientificして設定する

std::cout.precision(std::numeric_limits<double>::max_digits10 - 1);
std::cout << std::scientific <<  1.0/7.0 << '\n';

// C++11 Typical output
1.4285714285714285e-01

回答が多すぎると、1)基本2)固定/科学的レイアウト、または3)精度のいずれか1つだけに対応します。正確な回答が多すぎると、必要な適切な値が得られません。したがって、これは古い質問に対する答えです。

  1. どんな拠点?

A doubleは確かにbase 2を使用してエンコードされます。C++ 11での直接的なアプローチは、を使用して印刷することstd::hexfloatです。
10進数以外の出力が許容できる場合は、これで完了です。

std::cout << "hexfloat: " << std::hexfloat << exp (-100) << '\n';
std::cout << "hexfloat: " << std::hexfloat << exp (+100) << '\n';
// output
hexfloat: 0x1.a8c1f14e2af5dp-145
hexfloat: 0x1.3494a9b171bf5p+144

  1. それ以外の場合:fixedまたはscientific

A double浮動小数点型であり、固定小数点ではありません。

それ以外では何も印刷されないので使用しないでください。大規模な場合、それは多くの桁、おそらく何百もの疑わしい情報を出力します。std::fixeddouble0.000...000double

std::cout << "std::fixed: " << std::fixed << exp (-100) << '\n';
std::cout << "std::fixed: " << std::fixed << exp (+100) << '\n';
// output
std::fixed: 0.000000
std::fixed: 26881171418161356094253400435962903554686976.000000 

完全な精度で印刷するには、最初std::scientificに「科学表記法で浮動小数点値を書き込みます」を使用します。小数点以下の6桁のデフォルトは、次の点で処理されるのに不十分な量です。

std::cout << "std::scientific: " << std::scientific << exp (-100) << '\n';  
std::cout << "std::scientific: " << std::scientific << exp (+100) << '\n';
// output
std::scientific: 3.720076e-44
std::scientific: 2.688117e+43

  1. どのくらいの精度(合計桁数)?

Aは、doubleバイナリベース2つのエンコードこれは、多くの場合、53ビットである2の様々なパワーと同じ精度を使用してエンコード。

[1.0 ... 2.0)2 53種類ありdouble
[2.0 ... 4.0)2 53種類ありdouble
[4.0 ... 8.0)2 53種類ありdouble
[8.0 ... 10.0)2 / 8 * 2 53種類double

しかし、コードがN有効数字の10進数で出力される場合、組み合わせの数[1.0 ... 10.0)は9/10 * 10 Nです。

どのN(精度)を選択してもdouble、10進テキストとの間に1対1のマッピングはありません。 固定値Nが選択された場合、特定のdouble値で実際に必要な値よりもわずかに多いまたは少ない場合があります。エラーが少なすぎる(a)以下)または多すぎる(以下)可能性がありますb)

3候補N

a)Ntext--textから変換する場合は、soを使用して、doubleすべてのテキストが同じになるようにしますdouble

std::cout << dbl::digits10 << '\n';
// Typical output
15

B)を使用してNから変換するときにdouble-text- double我々は同じ到着doubleすべてについてdouble

// C++11
std::cout << dbl::max_digits10 << '\n';
// Typical output
17

max_digits10が使用できない場合は、基数2および基数10の属性によりdigits10 + 2 <= max_digits10 <= digits10 + 3digits10 + 3十分な10進数が出力されることを保証するために使用できることに注意してください。

c)N値によって異なるを使用します。

これは、コードが最小限のテキスト(N == 1)またはa の正確なdoubleN == 1000-ishの場合)を表示する必要がある場合に役立ちますdenorm_min。しかし、これは「作業」であり、OPの目標ではない可能性があるため、脇に置かれます。


通常、b)は「double完全な精度で値を出力する」ために使用されます。一部のアプリケーションは、a)過剰な情報を提供しないことでエラーを優先する場合があります。

桁数がので、小数点の後に印刷するように設定する数字が印刷されています。コードは総桁数を必要とするため、で呼び出されます。.scientific.precision()1 + .precision()max_digits10.precision()max_digits10 - 1

typedef std::numeric_limits< double > dbl;
std::cout.precision(dbl::max_digits10 - 1);
std::cout << std::scientific <<  exp (-100) << '\n';
std::cout << std::scientific <<  exp (+100) << '\n';
// Typical output
3.7200759760208361e-44
2.6881171418161356e+43
//1234567890123456  17 total digits

同様のCの質問


正解です。ただし、いくつかの備考:precision()科学モードの小数点以下の桁数を設定するのはあなたです。を指定しないとscientific、指数を除いた総桁数が設定されます。数値によっては、まだ科学的な出力が得られる可能性がありますが、指定した桁数よりも少ない桁数になる可能性もあります。例:のcout.precision(3); cout << 1.7976931348623158e+308; // "1.8e+308"結果はprintf異なる場合があります。気を付けなければならない混乱すること。
シンプルトン

後世のために、printfを使用する科学モードでのすべての倍数の正確な文字列表現を保証するために必要なバッファー長char buf[DBL_DECIMAL_DIG + 3 + 5]; sprintf(buf, "%.*g", DBL_DECIMAL_DIG, d);は次のとおりです。 DBL_MAX_10_EXP = 308)。したがって必要な文字の総数は25である
阿呆

最初のコメントを編集できないため、ここでもう一度説明します。科学モードのもう1つの問題は、指数出力を使用しないことを決定する可能性があり、浮動小数点出力をまったく使用しないことを決定する場合さえあります。つまり、1.0を「1」として出力します。これは、シリアライゼーション/デシリアライゼーションのコンテキストで問題になる可能性があります。"%#。* g"を使用して小数点を強制的に出力することができますが、これには#...なしではなく、後続のゼロが多数追加されるという欠点があります
Simpleton


0

最も移植性の高い...

#include <limits>

using std::numeric_limits;

    ...
    cout.precision(numeric_limits<double>::digits10 + 1);
    cout << d;

16
気になる:なぜ「+1」なのか?
エリック・マレンファント2009

0

ostream :: precision(int)を使用

cout.precision( numeric_limits<double>::digits10 + 1);
cout << M_PI << ", " << M_E << endl;

譲ります

3.141592653589793, 2.718281828459045

なぜ「+1」と言わなければならないのか、私には手掛かりがありませんが、それから得られる余分な数字は正しいです。


3
numeric_limits <unsigned char> :: digits10は2です。これは、2桁の0から99までの10進数を含むことができるためです。255 ..を含めることもできますが、256、257 ... 300などを含めることはできません。このため、digits10は3ではありません。このようなことを克服するために「+1」が追加されていると思います。
Dmitriy Yurchenko 2013

0

これにより、ドットの後に小数点以下2桁までの値が表示されます。

#include <iostream>
#include <iomanip>

double d = 2.0;
int n = 2;
cout << fixed << setprecison(n) << d;

こちらをご覧ください: 固定小数点表記

std :: fixed

固定浮動小数点表記を使用strストリームの浮動フィールド形式フラグを固定に設定します。

floatfieldがfixedに設定されている場合、浮動小数点値は固定小数点表記を使用して書き込まれます。値は、精度フィールド(精度)で指定された小数部の桁数とまったく同じで、指数部はありません。

std :: setprecision

小数精度の設定出力操作で浮動小数点値をフォーマットするために使用される小数精度を設定します。

浮動小数点を表すためのIEEE標準に精通している場合は、標準の範囲外で完全精度で浮動小数点を表示することは不可能であることがわかります。つまり、常に実際の値の丸め。

最初に値がスコープ内にあるかどうかを確認する必要があります。ある場合は、次を使用します。

cout << defaultfloat << d ;

std :: defaultfloat

デフォルトの浮動小数点表記を使用strストリームのfloatfield形式フラグをdefaultfloatに設定します。

floatfieldがdefaultfloatに設定されている場合、浮動小数点値はデフォルト表記法を使用して書き込まれます。表現は、ストリームの小数精度(精度)まで必要なだけ有効な数字を使用し、小数点の前後の両方の数字(存在する場合)をカウントします)。

これはのデフォルトの動作でもあります。つまりcout、明示的には使用しません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.