Я заметил небольшую ошибку в некоторых арифметических вычислениях с использованием double. Это действительно странно, всегда есть небольшая ошибка и / или дополнительная значащая цифра.
Сначала я использую atof для преобразования числа, которое имеет две значащие цифры, которые я читаю из текстового файла (затем я записываю их в вектор):
// Puts into vector
double ask_file, bid_file; // Values of ask and bid from file
double cur_conversion = 0.16;
ask_file = cur_conversion*atof(values[0].c_str());
bid_file = cur_conversion*atof(values[1].c_str());
Затем я делаю арифметику (из другого класса, два разных объекта):
diff = OKC->bid_val() - BV->ask_val(); // diff
diff2 = OKC->ask_val() - BV->bid_val(); // diff2
Это вывод:
BV Askfile: 245.267 Bidfile: 245.078
OKC Askfile: 248.82 Bidfile: 248.73
diff: 3.4628 diff2: 3.7416
Как видите, ошибка в обоих расчетах. diff = 3.463, а НЕ 3.4628. И diff2 = 3.742, а НЕ 3.7416.
Вы знаете, что происходит ??
Проблема в том, что в общем случае невозможно точно представить дробные десятичные значения, используя двоичные числа с плавающей запятой. Например, 0.1
представляется как 1.000000000000000055511151231257827021181583404541015625E-1
когда используешь double
(вы можете использовать это онлайн анализатор определить значения). При вычислении с этими округленными значениями количество необходимых двоичных цифр будет превышать число, которое может быть представлено, и значение будет дополнительно округлено, что приведет к большей ошибке. Конечно, все это кроется в Бумага Гольдберга на что указывает комментарий Эда Хила.
Существует ряд альтернативных представлений, которые вы можете использовать для точного вычисления с десятичными значениями. Если представление не использует представление произвольного размера, оно будет точно только в некотором диапазоне значений. Типичные варианты:
double
использует базу 2
но для десятичных вычислений вы бы использовали базу 10
,В зависимости от выбора реализации различные операции более или менее просты в реализации, а точные операции различаются. Например, за исключением представления с использованием рациональных операций деления всегда будут округлены, когда делитель не может быть представлен как произведение 2
а также 5
,
Какое представление будет работать лучше для вашего приложения, зависит от ваших потребностей. Если у вас есть только торговые цены в диапазонах, типичных для акций, может работать представление с фиксированной точкой. Если вам необходимо охватить все виды значений, с которыми вы можете столкнуться в финансах, например, национальные долги, а также процентные ставки, вам потребуется более 64 бит для представления с фиксированной запятой, и представление с десятичной плавающей запятой может быть лучшим представлением. В зависимости от того, нужно ли вам передавать и / или сохранять значения, представление с фиксированным размером может не потребоваться, и в этом случае другие представления могут быть разумным выбором.