2017-01-10 6 views
3

私は10^-15から10^-25までの非常に小さな数を使用するコードを扱っています。私はdoublelong doubleを使ってみましたが、0.0000000000000000000010に丸められているか、0.00000000000000002のような数字が0.00000000000000001999999999999のように誤った答えが出ました。C++非常に小さい浮動小数点数、preciscion

1/1000000という小さな割合でも最終回答に大きな違いがあるので、適切な修正がありますか?

#include <iostream> 
#include <math.h> 
#include <stdlib.h> 
#include <iomanip> 

using namespace std; 

int main() 
{ 
    double sum, a, b, c,d; 
    a=1; 
    b=1*pow(10,-15); 
    c=2*pow(10,-14); 
    d=3*pow(10,-14); 
    sum=a+b+c+d; 
    cout<<fixed; 
    cout<<setprecision(30); 
    cout<<" a : "<<a<<endl<<" b : "<<b<<endl<<" c : "<<c<<endl 
     <<" d : "<<d<<endl; 
    cout<<" sum : "<<sum<<endl<<endl; 
    a=a/sum; 
    b=b/sum; 
    c=c/sum; 
    d=d/sum; 
    sum=a+b+c+d; 
    cout<<" a : "<<a<<endl<<" b : "<<b<<endl<<" c : "<<c<<endl 
     <<" d : "<<d<<endl; 
    cout<<" sum2: "<<sum<< endl; 
    return 0; 
} 

予想される出力は次のようになります。

a : 1.000000000000000000000000000000 
b : 0.000000000000001000000000000000 
c : 0.000000000000020000000000000000 
d : 0.000000000000030000000000000000 
sum : 1.000000000000051000000000000000 

a : 1.000000000000000000000000000000 
b : 0.000000000000001000000000000000 
c : 0.000000000000020000000000000000 
d : 0.000000000000030000000000000000 
sum1: 1.000000000000051000000000000000 

しかし、私が手出力は次のようになります。

a : 1.000000000000000000000000000000 
b : 0.000000000000001000000000000000 
c : 0.000000000000020000000000000000 
d : 0.000000000000029999999999999998 
sum : 1.000000000000051100000000000000 

a : 0.999999999999998787999878998887 
b : 0.000000000000000999999997897899 
c : 0.000000000000019999999999999458 
d : 0.000000000000029999999999996589 
sum1: 0.999999999999989000000000000000 

私はlong doubledoubleを試してみましたが、でもboost_dec_floatが、私が手出力があります類似。

+0

構造体を番号の独自の表現にします。指数関数的には短く、残りは二倍になります。 このような小さな番号で作業しないようにユニットを変更することはできますか? – UKMonkey

+3

私はこれが重複ではないと主張します。 OPは正確に何が起きているのかを正確に知り、精度を高めるための解決策を求めています。 – SingerOfTheFall

+1

あなたの問題は、 '3 * pow(10、-14)'が0.000000000000030000000000000000ではなく0.000000000000029999999999999998として表示されているということです。それは二重の精度の限界にかなりあります。 –

答えて

0

気付いたように、数値は正確にバイナリで表現できず、ある程度丸められているために発生します。

これはboostタグでタグ付けされているため、ブースト値はboost.multiprecisionになります。それはcpp_dec_float_50データ型を提供し、50桁までの正確な計算が保証されます。これは、他のタイプとして使用されます。ドキュメントを高めるためによると

typedef boost::multiprecision::cpp_dec_float_50 value_type; 

value_type v1 = 1; 
value_type v2 = 3; 

value_type v3 = v1/v2; 

、これは出力が保証されているだけで、正確なビット:

cpp_dec_float_50 seventh = cpp_dec_float_50(1)/7; 
cpp_dec_float_50 circumference = boost::math::constants::pi<cpp_dec_float_50>() * 2 * seventh; 
std::cout.precision(std::numeric_limits<cpp_dec_float_50>::digits10); 
std::cout << circumference << std::endl; 
+0

正確な目標にもよるが、合理性も面白いかもしれない。 –

0

私はあなたが書いている賭け:

long double sum, a, b, c,d; 
a=1; 
b=1*pow(10,-15); 
c=2*pow(10,-14); 
d=3*pow(10,-14); 

問題は、powダブルのバージョンであることです。これは長いダブルバージョンではありません。引数の1つをlong doubleに強制する必要があります。

long double sum, a, b, c,d; 
a=1; 
b=1*pow(10.0L,-15); 
c=2*pow(10.0L,-14); 
d=3*pow(10.0L,-14); 
+0

これは、インテルのハードウェアで5〜6桁の精度の小数点以下桁数を購入することができます。 –

関連する問題