2016-07-20 19 views
0

テキストファイルから値を読み取ってdouble型に変換すると、 これらの値を画面上に出力する必要があります。これらの値は と同じになります。テキストファイル。文字列番号の精度を取得する

現在、印刷するとき、私は、 を最大精度を使用していると私はこのような結果を得る可能性があります:

テキスト値:8.994279313857e-317 印刷値:8.99427931385706e-317

各テキストファイルを と異なる値(同じテキストファイル内)の精度が異なる場合があります。 とこれらの値をメモリの懸念のための文字列として保存することはできません。

考えてみましょう。 精度のために別の符号なし整数をdouble型として格納することを考えていますが、文字列番号の精度を得る方法はありますか?

+0

* "テキストファイルから値を読み取り、それらをダブルに変換すると、これらの値を画面に出力する必要があります。これらはテキストファイルとまったく同じに見えるはずです。"数字を文字列として保存する必要があります。テキストファイルに基数10の数値が格納され、浮動小数点数がシステムに基底2として格納されていると仮定すると、送信先のコードにはソース番号を一度に表すことはできません。あなたは文字列を周りに保持する必要があります。これはまったく時期尚早の最適化であるため、スクラップして数字を文字列として保存します。それは**本当にシンプルです**。 – IInspectable

+0

おそらくboost.multiprecisionを試すことができます。しかし、それらを文字列として格納するのが最も簡単な解決策かもしれません。 –

+0

必要条件を満たすために最小限のメモリを使用する必要があるため、文字列では処理できません。S – nancyheidilee

答えて

0

ケーキを食べて食べることはできません! :)

つまり、文字列を正確に表現するには、文字列(*)を保存するだけで、メモリのコストを支払う必要はありません。

その場合、できることはlong doubleを使用することです。数値定数の最後にLを追加することがわかります。しかし、もちろん、これには限界があります(私たちのコンピュータにも限界があります)。さらに、スペースの無駄(および処理時間)は、必要としない数字にlong doubleを使用することになります。あなたが満たす精度は固定されていないと言いますからです。あなたがしたい場合

C02QT2UBFVH6-lm:~ gsamaras$ cat example.txt 
3.12345678912345678912345678 2.79 
C02QT2UBFVH6-lm:~ gsamaras$ g++ -Wall main.cpp 
C02QT2UBFVH6-lm:~ gsamaras$ ./a.out 
3.12345678912345679 
2.79000000000000000 

:私のマシン上を与える

#include <fstream> 
#include <vector> 
#include <cstdlib> 
#include <iostream> 
#include <limits> 

typedef std::numeric_limits<double> dbl; 

int main() { 
    std::ifstream ifile("example.txt", std::ios::in); 
    std::vector<long double> scores; 

    //check to see that the file was opened correctly: 
    if (!ifile.is_open()) { 
     std::cerr << "There was a problem opening the input file!\n"; 
     exit(1);//exit or do additional error checking 
    } 

    long double num = 0.0; 
    //keep storing values from the text file so long as data exists: 
    while (ifile >> num) { 
     scores.push_back(num); 
    } 

    std::cout.precision(dbl::max_digits10); // you can print more digits if you like, you won't the exact representation obviously 
    //verify that the scores were stored correctly: 
    for (int i = 0; i < scores.size(); ++i) { 
     std::cout << std::fixed << scores[i] << std::endl; 
    } 

    return 0; 
} 

:だから、あなたはそのコード(親切thisthis答えとstd::numeric limitsによって組み立て)であることを行うことができますさらに進むには、GMPを使用します。これは、「任意精度演算のためのフリーライブラリ」です。もちろん、これはメモリ使用量と処理時間の面では無料ではないので、は実際に2回考えてくださいそれを使用する前に!


* あなたは時期尚早最適化の犠牲者であると感じます。私があなただったら、文字列を格納して、これがどうなっているのかを見てみましょう。数字のデータ型を使う方が良いでしょう。プロジェクトが準備ができたら、あなたはどんな結果を得ているのか、達成された精度が「あなたの上司」を満足させるかを見てください。そうでない場合は、文字列(または)を使用します。

+0

'long double'は' double'よりも高い精度またはより大きな範囲を提供することは保証されていません。 80ビット浮動小数点表現をサポートするVisual Studioの最後のバージョンはVisual Studio 6 SP6でした。現在、両方の浮動小数点型は、Visual Studioを使用する場合、同じ表現([基本型(C++)](https://msdn.microsoft.com/en-us/library/cc953fe1.aspx)を参照)を使用します。 – IInspectable

+0

@IInspectable確かに、Visual studioで! :) – gsamaras

0

適切な方法は、任意の数値を表すクラスを忠実に使用することです。このような値を表現するには、任意の精度の整数クラスをスケール係数で使用できます。

#include <boost/multiprecision/cpp_int.hpp> 

// numeric = value/pow(10, scale) 
struct numeric { 
    /// arbitrary precision integer 
    boost::multiprecision::cpp_int value; 
    /// point position 
    int scale; 
}; 
// for example, 10.1 can be represented with the numeric class exactlty in difference to double : 
numeric n{101, 1}; // 101/pow(10, 1) 

あなたははstdする::文字列、数値クラスのオブジェクトを変換するヘルパー関数を使用することができ、そのような番号を印刷するには:

std::string to_string(const numeric& n) const 
{ 
    if (n.value.is_zero() && n.scale <= 0) 
    return "0"; 
    bool neg = n.value < 0; 
    std::string r; 
    { 
    std::ostringstream s; 
    s << (neg ? -n.value : n.value); 
    s.str().swap(r); 
    } 
    if (n.scale > 0) { 
    if (n.scale >= r.length()) { 
     r = std::string(n.scale - r.length() + 1, '0') + r; 
    } 
    r.insert(r.length() - n.scale, 1, '.'); 
    if (neg) 
     r = '-' + r; 
    } 
    else if (n.scale < 0) { 
    if (neg) 
     r = '-' + r; 
    r += std::string(-n.scale, '0'); 
    } 
    else { 
    if (neg) 
     r = '-' + r; 
    } 
    return std::move(r); 
} 

構築するために例えば、それは、以下のことのように定義することができますstd :: stringの数値オブジェクトです。ポイント位置(数値の位取り)を見つけ出し、ポイントを削除し、ポイント文字列からクリアしてcpp_intを初期化します。

+0

* "std :: stringから数値オブジェクトを構築するには..." * - そうではありません。 +/-符号(およびその情報を保持する)、千の区切り文字、または科学記法(たとえば101e-1)を考慮する必要があります。そしてそのすべての追加情報が保存されているので、節約量が少なくなり、単純に文字列を保存するだけでは不十分です。 – IInspectable

+0

@IInspectable:大丈夫ですが、regexで実装するのは難しくありません。 – AnatolyS

+0

* "それほど難しくありません" * - 私はあなたを信じようとしています。いったん正規表現を出すと、確実に動作します。しかし、これは私がしようとしていたことをすべて忘れてしまっています:浮動小数点リテラル(バイナリ表現に加えて)の元のフォーマットを再現するのに必要なすべての情報を保存したい場合、 。 – IInspectable

関連する問題