Как я могу безопасно привести от двойного к целому без потери данных - PullRequest
0 голосов
/ 11 мая 2019

У меня есть программа продажи / покупки акций, где пользователь может сказать, сколько акций он хочет купить и продать. Все работает нормально, пока пользователь не захочет продать акцию за 4,10 доллара за 5,10 доллара. Чтобы сделать математику проще с плавающей точкой, я конвертирую двойное в целое: 10.10 становится 1010 и так далее. Всякий раз, когда я разыгрываю 4.10 в int, оно становится 409, и то же самое происходит для 5.10.

Деньги хранятся в классе, доллары. Внутри этого класса, когда я вызываю конструктор, я могу вызвать Dollars(int cents): cents(cents) {} или Dollars(double dollars): cents(0) { *this = dollars; }. Когда используется двойной конструктор, он использует следующий cents = (int)(dollars * 100.0); для приведения данного двойного к целому числу.

Я пытался использовать (int)(double) метод приведения внутри класса для преобразования в int, и я также пробовал приводить в int ранее и использовать конструктор int, но ни один из них не сработал.

Я ожидаю, что выход этого броска будет 410, когда я кормлю его 4.10, но он всегда выходит на 4.09.

1 Ответ

1 голос
/ 12 мая 2019

Не используйте поплавки для валюты. Также 4.10 * 100, вероятно, 409.999999 ... и преобразование в int просто усекает. В этом случае вы получите более точные результаты, сначала позвонив std::round. Это не решит все ошибки округления. Все еще будут случаи, когда результат не будет корректным только потому, что double имеет 52-битную мантиссу и int может / будет 64-битной, если скомпилирована для платформы x64.

Последняя проблема иногда может быть решена с помощью long double, если есть поддержка. Это sizeof(long double)>sizeof(double), что не гарантируется.

Самая простая правильная реализация - просто использовать uint64_t и выполнять все вычисления, например, центов. Тогда все математические операции точны. В реальной жизни, когда банк рассчитывает проценты, он также округляет результат, нет необходимости в плавающей точности. Правильная печать тогда: cout<<amount/100<<"dollars "<<amount%100<<"cents";

...