0

次のコードを考えると:

istringstream i("2.11099999999999999999");

double d;
if (!(i >> d)) {d = 0;}

cout << d << endl;

出力は2.111です。

長い数値、浮動小数点数 (浮動小数点を含む) を操作できるようにしたいのですが、istringstreamdouble に変換すると、丸められた数値が得られます。

どうすればそれを防ぐことができますか? 指定された入力をそのまま維持するにはどうすればよいですか?

よろしく

4

5 に答える 5

2

この場合、防ぐことはできません。doubleは値 2.11099999999999999999 を正確に表すことができず、2.1109999999999999999と 2.111 を区別する値はありません。

http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.htmlで、知っておくべきことや、さらに多くのことを知ることができます。

丸められた値と丸められていない値を区別する値を表すことができる別の例を使用する場合、次のdoubleようにすることができます。

#include <iostream>
#include <sstream>
#include <iomanip>

int main() {
    std::istringstream iss("2.1109999");
    double d;
    iss >> d;
    std::cout << d << "\n";
    std::cout << std::setprecision(10) << d << "\n";
}

出力:

2.111
2.1109999

dただし、に格納されている値は正確ではないことに注意してください2.1109999

std::cout << std::setprecision(20) << d << "\n";

出力 (私のマシンでは、一部のランタイム ライブラリが 20 sf にまったく出力されないため、異なる場合があります):

2.1109998999999999292

これは、値をdecimal ではなくbinarydoubleで格納するためです。そのため、2 進数の端数のみを表すことができます。2.1109999 は、基本的に 3 分の 1 が終了小数ではないのと同じ理由で、終了 2 進分数ではありません。

したがって、指定された入力をそのまま保持する (つまり、その数値を正確に表す) には 2 つの方法があります。

  1. に変換せずdouble、文字列のままにしておきます。
  2. に変換しないdoubleでください。代わりに、小数および/または有理数を表すライブラリを見つけるか作成してください。たとえば、GMP ライブラリにはBoost.Rationalmpq_tがあります。
于 2012-12-04T09:35:25.467 に答える
0

数学の世界では無数の数があり、adoubleは有限です。つまり、64 ビットに収まるので、そのような値のサブセットのみが正確に表現されます。また、実際には 2.111 も正確に表現されていません。数値は小数点で印刷されますが、実際には仮数 (52 ビットの精度) と指数と符号ビットである 2 進数を使用するためです。

仮数部の精度は約 52 ビットなので、2 の 52 乗は 4,503,599,627,370,496 です。

ご覧のとおり、この数値は最初の 4 桁の後に 15 桁あるため、10 進数の精度は 15 桁になります。

ほとんどの場合、この精度で十分です。より精度が必要な場合や、大きな数と小さな変更が必要な特殊なケースでは、専門的な技術を採用する必要があります。それを提供するライブラリがいくつかあります。

于 2012-12-04T09:46:40.190 に答える
0

ここでは 2 つの別個の変換が行われています。テキストから double への変換 ( iss >> d) と、その double からテキストへの変換 ( std::cout << d) です。最初のものは、入力テキストの最良の近似値をdouble変数に格納します。2 つ目はデフォルトの精度を使用します。その精度に合わせて値を丸め、末尾のゼロを抑制します。それがあなたが見る理由です2.111。桁数を増やしたい場合は、 を使用setprecisionして出力の桁数を増やします。他の人が言ったように、約 15 桁 (入力または出力) を超えるものはナンセンスです。

于 2012-12-04T14:46:54.733 に答える
0

言ったように、そのような精度を持つことはできません。ここで説明されているように、いつでも表示桁数を増やすことができます:精度を上げる

于 2012-12-04T09:38:00.243 に答える
0

数値は、2 進数表現である double 以外の形式で格納する必要があります。

数値を 10 進表現として格納するライブラリを探してみてください。boost にはhttp://svn.boost.org/svn/boost/sandbox/big_number/libs/multiprecision/doc/html/index があることがわかっています。 htmlですが、他にもたくさんあります。

これが少し重い解決策のように思われる場合は、istringstream を一度に 1 文字ずつ読み取ってみてください。数字の場合は、char から int に変換してから、配列に格納してください。

テストされていないコード

string s = "2.11099999999999999999";
char num[s.size()];
for (int i = 0; i < s.size(); ++i) {
  if (isdigit(s[i])
    num[i] = s[i] - '0';
  else
    num[i] = s[i];
}
于 2012-12-04T11:00:50.580 に答える