0

Моя функция, чтобы избавиться от дробной части двух дублей при сохранении их соотношения:Как преодолеть неточность двойной точности?

void enlarge(double &a, double &b) 
{ 
    while (a != trunc(a) || b != trunc(b)) 
    { 
     a *= 10; 
     b *= 10; 
     //output added for debugging 
     cout << "a = " << a << ", b = " << b << endl; 
     cout << "trunc(a) = " << trunc(a) << ", trunc(b) = " << trunc(b) << endl; 
     cout << "a == trunc(a): " << to_string(a == trunc(a)) << ", b == trunc(b): " << to_string(b == trunc(b)) << endl; 
     //to see output step by step 
     string asd; 
     cin >> asd; 
    } 
} 

выход, когда он перестает работать правильно:

a = 0.876, b = 99.9 
trunc(a) = 0, trunc(b) = 99 
a == trunc(a): 0, b == trunc(b): 0 
a 
a = 8.76, b = 999 
trunc(a) = 8, trunc(b) = 999 
a == trunc(a): 0, b == trunc(b): 1 
a 
a = 87.6, b = 9990 
trunc(a) = 87, trunc(b) = 9990 
a == trunc(a): 0, b == trunc(b): 1 
a 
a = 876, b = 99900 
trunc(a) = 876, trunc(b) = 99900 //This is where it stops working 
a == trunc(a): 0, b == trunc(b): 1 //Notice how 876 != 876 
a 
a = 8760, b = 999000 
trunc(a) = 8760, trunc(b) = 999000 
a == trunc(a): 0, b == trunc(b): 1 

Что мне делать в этой ситуации?

+0

A) Его довольно сложно найти ошибки в коде, которые вы не показываете. B) std :: cout не печатает числа до полной точности. Здесь есть несколько вопросов по этой теме. Просто найдите его. Если вам нужен формат вывода, я бы использовал printf. C) Чтобы ответить на ваш вопрос: используйте более точный тип номера. – user463035818

+0

Взгляните на это: http://stackoverflow.com/questions/10334688/how-dangerous-is-it-to-compare-floating-point-values ​​ – NathanOliver

+1

Считаете ли вы использование * фиксированной точки * математики? Вы можете получить лучшую точность. –

ответ

1

Проблема в том, что первоначальный номер не был ровно .876, хотя это не сильно отличалось. Поэтому вам, возможно, придется умножить на 10 довольно много раз, чтобы получить это целое число.

Кроме того, обратите внимание, что если число было немного меньше, чем .876, в 1000 раз число будет немного меньше, чем 876,0 и TRUNC (875.99999999 ...) является 875, а не 876.

Вы могли бы рассмотреть некоторые пороговое значение, где число «достаточно близко» к целому числу. например, вместо того, чтобы использовать a==trunc(a), вы можете использовать тест

abs(a - round(a)) < 1e-6 

Наконец, если вы хотите, чтобы быть точным, то вы могли бы умножить на 2 на каждом шаге, а не на 10. Вы теряете немного Прецизионный каждый раз вы умножаетесь на 10, потому что 10 не является степенью 2. Умножение на 2 приведет к получению целого числа после максимум 52 умножений.

+0

Зачем беспокоиться о 'double', если бы вы могли просто использовать _fixed point math_? –

+0

@ πάνταῥεῖ: Если бы я мог использовать фиксированную точку * просто *, я бы, вероятно, использовал ее чаще, но ее просто использовать в очень ограниченных областях проблем, даже с внешними библиотеками. В самой ссылке, которую вы предоставляете, Фаулер жалуется на отсутствие поддержки валюты в стандартных библиотеках, например. Поэтому я беспокоюсь о «двойном», когда мне не нужно беспокоиться о создании среды с фиксированной точкой :) – rici

1

«Моя функция избавиться от дробной части из двух двойников , сохраняя при этом их соотношении

Вы, вероятно, хотите использовать значение с фиксированной точкой, а не double вообще , чтобы обеспечить правильную работу. Что-то вроде описанного в Money Pattern, который был разработан для преодоления этих проблем.

Общая идея: у вас есть значение int, которое удерживает его умноженным (внутренним) представлением в соответствии с требуемой точностью. Поэтому, если вам нужна точность в 3 десятичных точки, вы умножаете это (внутренне), представляя значение с 1000, 4 десятичными точками -> * 10000, aso.

Если вам нужно обрабатывать огромные значения, которые нельзя удерживать в виде (представлены как) переменную целочисленного значения long long, существуют (не стандартные) большие целые управляющие библиотеки, которые вы также можете использовать для этого.

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

  • Нет связанных вопросов^_^