2017-01-10 6 views
3

Я имею дело с кодом, который использует очень маленькие номера порядка 10^-15 до 10^-25. Я пробовал использовать double и long double, но я получаю неправильный ответ, так как либо 0.000000000000000000001 округляется до 0, либо число, подобное 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 

Я попытался double, long double и даже boost_dec_float, но на выходе я получаю аналогичный.

+0

Создайте структуру, которая является вашим собственным представлением числа; с коротким для экспоненциального и двойным для остальных; Или, может быть, измените единицы так, чтобы вы не работали с такими маленькими номерами? – UKMonkey

+3

Я бы сказал, что это не дубликат. OP точно знает, что происходит, и просит решение повысить точность. – SingerOfTheFall

+1

Итак, ваша проблема заключается в том, что '3 * pow (10, -14)' отображается как 0,000000000000029999999999999998, а не 0,000000000000030000000000000000. Это в значительной степени зависит от точности двойной. –

ответ

0

Как вы заметили, это происходит потому, что цифры не могут быть точно представлены в двоичном формате и округлены до определенной степени.

Теперь, поскольку вы отметили это знаком boost, 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 будет double версия pow - не длинная двойная версия. Вам нужно заставить один из аргументов удваивать:

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 дополнительных десятичных цифр точности на оборудовании Intel. –

Смежные вопросы