Проблема с Double

divankin

Senjor developer
13.08.2009
182
0
#1
Как вы думаете, что будет если выполнить данный код?
Dim rest As Double
rest = 42430.11
rest = rest - 10607.53
rest = rest - 10607.53
rest = rest - 10607.53
rest = rest - 10607.52
Print rest

У меня данный код выводит в консоль не ноль, а 1,81898940354586Е-12
Можно ли где-то подкрутить какие-нибудь настройки клиента или сервера, чтобы избежать таких остатков, а не менять код , везде где используются сравнения вычисляемых значений типа Double?

Клиенты: 6.5.5, 7.0.2 Win32
Сервера: 7.0.3FP1 Linux, 8.0.2FP1 Win32
 

NickProstoNick

Статус как статус :)
Lotus team
22.08.2008
1 802
21
#2
Ничего гадкого. Просто тебе возвращается приближенное к 0 значение.
Просто надо использовать округление Round.
Я решал такую проблему умножением и делением 1000 и отсечением возможных знаков после запятой. Мне нужна была точность до 3-го знака
Код:
Dim rest As Double
rest = 42430.11 * 100
rest = rest - 10607.53 * 100
rest = rest - 10607.53 * 100
rest = rest - 10607.53 * 100
rest = rest - 10607.52 * 100
Print rest / 100
 

Omh

Lotus team
04.07.2007
2 210
1
#3
Тоже не ноль.
Интересная ситуация, я когда-то встречался с этим.
Не помню как тогда решил, но наверно смотрел в сторону
Код:
round
.
 

ToxaRat

Чёрный маг
Lotus team
06.11.2007
3 231
17
#4
10607.53
внести в переменную типа double
так как в явнов виде оно конвертится почти в long
ко всему прочему тут нужно использовать тип Currency - валюта, там меньше "инженерных приколов"
 

divankin

Senjor developer
13.08.2009
182
0
#5
Гадкость в том, что об этой особенности нужно помнить при всех операциях с типом Double. Я как-то не ожидал, что такие проблемы могут возникнуть при сложении и вычитании.
В боевой программе последнего вычитания не было, а вместо него было сравнение. И программа выдавала, что 10607.52 > 10607.52
 
13.03.2009
625
1
#6
Гадкость в том, что об этой особенности нужно помнить при всех операциях с типом Double. Я как-то не ожидал, что такие проблемы могут возникнуть при сложении и вычитании.
В боевой программе последнего вычитания не было, а вместо него было сравнение. И программа выдавала, что 10607.52 > 10607.52
это азы программирования. при работе с числами с плавающей точкой:
1. нельзя сравнивать число их с нулем
2. нельзя проверять два таких числа на равенство.( тот же п. 1 )
обычно, вводится константа - т.н. "машинный ноль" , и проверяется abs( floatNumber ) < epsilon.
для большинства реальных задач 1e-6 - достаточная точность.
Ограничение это системное и никак с лотусом не связано.
Java:
double a = 1.1 - 1;
double b = 0.1;
System.out.println( a-b );
Результат: 8.326672684688674E-17
Для уяснения, что данная проблема не зависит от вида операции:
двоичное разложение десятичной дроби 0.1 - бесконечная дробь 0.0(0011), поэтому 0.1 невозможно сохранить в double без потери точности.
 

lmike

нет, пердело совершенство
Премиум
27.08.2008
6 567
263
#7
и есть тип curency
и эта проблема не специфична домине (как указал коллега)
 

Akupaka

А че я?.. О.о
04.10.2007
3 360
1
#8
это азы программирования
ой! ну хоть кто-то умный вещь сказал! а то я думал, что так и будем думать, что лотус - корень всех на свете проблем...

Гадкость в том, что об этой особенности нужно помнить при всех операциях с типом Double
ну зачем обо всех? обычно нужна точность какого-то результата, а для этого достаточно одной таблетки, т.е. одной операции приведения конечного результата к нужному виду (отображения)