web-dev-qa-db-ja.com

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

だから私は私の 最後の質問 に対する答えを得ました(なぜ私はそれを考えなかったのかわかりません)。期待していなかったときに丸められたdoubleを使ってcoutを印刷していました。フル精度でcoutdoubleを印刷させるにはどうすればよいですか?

292
Jason Punyon

精度を直接std::coutに設定し、 std::fixed フォーマット指定子を使用することができます。

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

Floatまたはdoubleの最大精度を取得するために#include <limits>を使用できます。

#include <limits>

typedef std::numeric_limits< double > dbl;

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

std::setprecision を使います。

std::cout << std::setprecision (15) << 3.14159265358979 << std::endl;
60
Paul Beckingham

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

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
他の属性についての詳細.

23
Martin York

入出力ストリームの方法は不格好です。私は 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

13
Timothy003

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は、小数点の前後の桁数を表します。


set_precision(max_digits10)をstd :: fixedと共に使用しないでください。
固定表記では、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>
10
Daniel Laügt

完全な精度とは、意図した値に最適な近似を示すのに十分な精度を意味すると想定しますが、doubleはベース2表現を使用して格納され、ベース2は1.1正確に。 full-fullの実際のdoubleの精度(ROUND OFF ERRORなし)を取得する唯一の方法は、バイナリビット(または16進ニブル)を出力することです)。これを行う1つの方法は、doubleunionに書き込んでから、ビットの整数値を出力することです。

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

これにより、doubleの100%正確な精度が得られ、人間がIEEE double形式を読み取れないため、まったく読めなくなります。 Wikipedia には、バイナリビットの解釈方法に関する優れた記事があります。

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

std::cout << std::hexfloat << 1.1;
9
Mark Lakata

Coutを使用してdoublename__値を全精度で出力するにはどうすればよいですか?

hexfloatname__を使用する
scientificname__を使用して精度を設定します

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つのみに対処しています。precisionの回答が多すぎると、必要な正しい値が得られません。それ故、これは古い質問に対する答えです。

  1. 何ベースですか?

doublename__は確かに基数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. それ以外の場合:fixedname__またはscientificname__?

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

not を使用すると、std::fixedを使用しても、小さいdoublename__を0.000...000以外のものとして表示できません。 doublename__が大きい場合、それは多くの数字を出力します。おそらく100/は疑わしい情報です。

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. 精度はいくらですか(合計桁数)。

2進数2を使用してエンコードされたdoublename__は、さまざまな2の累乗の間で同じ精度をエンコードします。これは通常53ビットです。

[1.0 ... 2.0)2があります53 異なるdoublename__、
[2.0 ... 4.0)2があります53 異なるdoublename__、
[4.0 ... 8.0)2があります53 異なるdoublename__、
[8.0 ... 10.0)2/8 * 2あり53 異なるdoublename__。

それでも、コードがNname__の有効数字で10進数で表示される場合、組み合わせの数[1.0 ... 10.0)は9/10 * 10です。N

どのNname__(精度)が選択されても、doublename__と10進数テキストの間に1対1のマッピングはありません。 固定のNname__が選択された場合、時々、それは特定のdoublename__値のために本当に必要とされるよりわずかに多いかまたは少ないことがあります。エラーが少なすぎる(a)以下)または多すぎる(b)以下)場合にエラーが発生する可能性があります。

3人のNname__の候補者:

a)Nname__を使用すると、text -doublename __- textから変換するときに、すべてのdoublename__に対して同じテキストが表示されます。

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

b)Nname__を使用すると、doublename __-text -doublename__から変換するとき、すべてのdoublename__に対して同じdoublename__が表示されます。

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

max_digits10が利用できない場合、2進数と10進数の属性digits10 + 2 <= max_digits10 <= digits10 + 3のため、十分な小数桁数が印刷されるようにするためにdigits10 + 3を使うことができます。

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

これは、コードが最小のテキスト(N == 1)またはexactの値(doublename__)(N == 1000-ishの場合はdenorm_min)を表示したい場合に便利です。しかし、これは「仕事」であり、OPの目標ではないと思われるので、それは取っておきます。


通常、b)は「doublename__値を完全精度で印刷する」ために使用されます。いくつかのアプリケーションは、あまりにも多くの情報を提供していないことでエラーを起こすことを好むかもしれません。

.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

似たようなCの質問

4
chux
printf("%.12f", M_PI);

%12fは、12桁の精度の浮動小数点を意味します。

3
Maister

coutは、印刷物の精度とフォーマットを変更するために呼び出すことができる一連のメソッドを持つオブジェクトです。

Setprecision(...)操作がありますが、印刷幅などの他のものも設定できます。

IDEのリファレンスでcoutを調べてください。

1
Uri

Ostream :: precision(int)を使って

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

収まる

3.141592653589793, 2.718281828459045

なぜあなたは "+1"と言わなければならない私は手がかりを持っていないが、あなたがそれから出る余分な数字は正しいです。

0
Jann

ほとんどのポータブル...

#include <limits>

using std::numeric_limits;

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