Чудеса с плавающей точкой
От: Stone78 Россия  
Дата: 20.10.08 09:07
Оценка: :)))
Есть сервер приложений, одна из функций возвращает сумму в копейках в виде целого числа (int). Однажды выяснилось, что одна копейка "потерялась", в БД одна сумма, на клиенте она пришла на копейку меньше.
Сумму в результирующем классе устанавливает такой код:

double sum;

// ...
// Здесь расчет суммы
// ...

result.Sum = (Int32)(sum * 100);


Выяснилось, что при sum = 38.87 в result.Sum получается 3886!
Интересно, что если в Visual Studio в окне QuickWatch набрать 38.87*100, получается 3886.99999999995. Причем если умножать на 10 или 1000, то все ОК, получается соответственно 388.7 и 38870.0.

Что бы это значило? Теперь перевод в копейки через округление что ли делать?!
Re: Чудеса с плавающей точкой
От: fmiracle  
Дата: 20.10.08 09:20
Оценка:
Здравствуйте, Stone78, Вы писали:

S>Выяснилось, что при sum = 38.87 в result.Sum получается 3886!


О сколько нам открытий чудных готовит просвященья дух...


S>Что бы это значило? Теперь перевод в копейки через округление что ли делать?!


Это значит что теперь уже пора:

1. прочитать как работает float и double и хотя бы почему они называются числами с плавающей точкой.
2. хранить деньги в decimal
3. Посмотреть заодно код на наличие точного равенства с числами с плавающей точкой (типа sum == 0). Не удивлюсь если такие в коде тоже найдутся. А ты удивишься, когда увидишь, как они регулярно не срабатывают
Re: Чудеса с плавающей точкой
От: Александр Кузнецов Россия  
Дата: 20.10.08 09:24
Оценка: 5 (2)
Здравствуйте, Stone78, Вы писали:

S>Что бы это значило? Теперь перевод в копейки через округление что ли делать?!


Тема проблем с округлением поднималась уже неоднократно. К VS это никакого отношения не имеет. См., например,http://www.rsdn.ru/Forum/message/3010081.flat.aspx
Автор: zbanned
Дата: 03.07.08
. А вообще, поиск рулит.

Для работы с деньгами вообще лучше использовать специально для этого предназначенный тип decimal.
"Пишите код так, как будто сопровождать его будет склонный к насилию психопат, который знает, где вы живете". (с) Макконнелл, "Совершенный код".
Re: Чудеса с плавающей точкой
От: samius Япония http://sams-tricks.blogspot.com
Дата: 20.10.08 09:25
Оценка:
Здравствуйте, Stone78, Вы писали:

S>Что бы это значило? Теперь перевод в копейки через округление что ли делать?!


А кто вам сказал, что отбрасывание дробной части после умножения на 100 — адекватно округлит double до копеек?
Re: Чудеса с плавающей точкой
От: _d_m_  
Дата: 20.10.08 09:29
Оценка:
Здравствуйте, Stone78, Вы писали:


S>Выяснилось, что при sum = 38.87 в result.Sum получается 3886!

S>Интересно, что если в Visual Studio в окне QuickWatch набрать 38.87*100, получается 3886.99999999995. Причем если умножать на 10 или 1000, то все ОК, получается соответственно 388.7 и 38870.0.

S>Что бы это значило? Теперь перевод в копейки через округление что ли делать?!


В тысячный раз уже...
А что поиском воспользоваться не судьба?
RTFM!!!

В этом сообщении
Автор: _d_m_
Дата: 19.05.08
две ссылки — сходи по ним. Да всю ветку обсуждения нелишне почитать.
Re: Чудеса с плавающей точкой
От: Aen Sidhe Россия Просто блог
Дата: 20.10.08 09:33
Оценка:
Здравствуйте, Stone78, Вы писали:

S>Что бы это значило? Теперь перевод в копейки через округление что ли делать?!


1. Да.
2. Что будет, если у вас будет сумма больше 250 миллионов рублей?
3. Для денег есть специальный тип decimal.
С уважением, Анатолий Попов.
ICQ: 995-908
Re[2]: Храните деньги в сберегательной кассе
От: Spiceman  
Дата: 20.10.08 10:06
Оценка: :))) :))
Здравствуйте, fmiracle, Вы писали:

[оффтопик]
F>2. хранить деньги в decimal

Решение проблемы на время мирового финансового кризиса.
[/оффтопик]
Re[2]: Чудеса с плавающей точкой
От: Sinclair Россия https://github.com/evilguest/
Дата: 20.10.08 10:28
Оценка: :)
Здравствуйте, Aen Sidhe, Вы писали:
AS>2. Что будет, если у вас будет сумма больше 250 миллионов рублей?
Какой вопрос! Какой вопрос...
Вот лично я считаю, что если у меня будет сумма больше 250 миллионов рублей, то вопросы округления копеек будут беспокоить меня меньше всего...
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[3]: Чудеса с плавающей точкой
От: _FRED_ Черногория
Дата: 20.10.08 10:31
Оценка:
Здравствуйте, Sinclair, Вы писали:

AS>>2. Что будет, если у вас будет сумма больше 250 миллионов рублей?

S>Какой вопрос! Какой вопрос...
S>Вот лично я считаю, что если у меня будет сумма больше 250 миллионов рублей, то вопросы округления копеек будут беспокоить меня меньше всего...

До тех пор, пока на указанную копейку ты не ошибёшься в налоговой декларации
Help will always be given at Hogwarts to those who ask for it.
Re[4]: Чудеса с плавающей точкой
От: Sinclair Россия https://github.com/evilguest/
Дата: 20.10.08 11:03
Оценка:
Здравствуйте, _FRED_, Вы писали:
_FR>До тех пор, пока на указанную копейку ты не ошибёшься в налоговой декларации
Да ну. Ну насчитают мне пеней на эту копейку — там за десять лет и рубля не набежит.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[3]: Чудеса с плавающей точкой
От: alzt  
Дата: 20.10.08 11:10
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, Aen Sidhe, Вы писали:

AS>>2. Что будет, если у вас будет сумма больше 250 миллионов рублей?
S>Какой вопрос! Какой вопрос...
S>Вот лично я считаю, что если у меня будет сумма больше 250 миллионов рублей, то вопросы округления копеек будут беспокоить меня меньше всего...

Бюджет, у которого дебит с кредитом не сходятся, не вызывает доверия.
Re: Чудеса с плавающей точкой
От: alzt  
Дата: 20.10.08 11:13
Оценка:
Здравствуйте, Stone78, Вы писали:

S>
S>double sum;

S>// ...
S>// Здесь расчет суммы
S>// ...

S>result.Sum = (Int32)(sum * 100);
S>


S>Выяснилось, что при sum = 38.87 в result.Sum получается 3886!

S>Интересно, что если в Visual Studio в окне QuickWatch набрать 38.87*100, получается 3886.99999999995. Причем если умножать на 10 или 1000, то все ОК, получается соответственно 388.7 и 38870.0.

S>Что бы это значило? Теперь перевод в копейки через округление что ли делать?!


Кратко — double\float и прочие типы с плавающей точкой не предназначены для точных вычислений.
Используй, хотя бы, int.
Идея следующая
int sum = 0;//в копейках

// ...
// Здесь расчет суммы
// Все числа умножаются на 100.
// ...

result.Sum = (Int32)(sum);


Плюс посмотри тип Decimal и для чего он предназначен.
Re: Чудеса с плавающей точкой
От: Stone78 Россия  
Дата: 20.10.08 11:43
Оценка:
Всем спасибо, разобрался.
Изменил на Decimal, все теперь ОК.
Век живи, век учись...
Re[2]: Чудеса с плавающей точкой
От: nikov США http://www.linkedin.com/in/nikov
Дата: 21.10.08 11:40
Оценка: 2 (1) +1
Здравствуйте, fmiracle, Вы писали:

F>1. прочитать как работает float и double и хотя бы почему они называются числами с плавающей точкой.

F>2. хранить деньги в decimal

Плавающая точка здесь совсем не при чем.

Decimal Structure

A decimal number is a floating-point value that consists of a sign, a numeric value where each digit in the value ranges from 0 to 9, and a scaling factor



Дело в том, что матисса у float и double умножается на степень двойки, а не десятки.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.