Что нового

Сравнение вещественных чисел

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5 379
Репутация
2 711
Есть в AutoIt один досадный баг/особенность. Иногда невозможно "по человечески" сравнивать два вещественных числа (см. пример). В свое время, это доставляло мне много неудобств...

Код:
$i = 0
While $i <= 1
	ConsoleWrite($i & @CR)
	$i += 0.01
WEnd


Мне лень было выяснять причины и т.д, я просто ввел функцию _Precise(), которая округляет мантиссу вещественного числа до максимального действительного значение. И все проблемы исчезли...

Код:
$i = 0
While $i <= 1
	ConsoleWrite($i & @CR)
;	$i += 0.01
	$i = _Precise($i + 0.01)
WEnd

Func _Precise($Value)
	Return Round($Value, 15)
EndFunc   ;==>_Precise


Еще раз убеждаюсь, что без "танцев с бубном" производить математические вычисления в AutoIt не получается.



Добавлено:
Сообщение автоматически объединено:

Еще один пример.

Код:
$A = 0.0004
$B = 0.02
$C = 0.000016
$D = 2

$X = $A * $B ; $X = 0.000008
$Y = $C / $D ; $Y = 0.000008

ConsoleWrite($X & @CR)
ConsoleWrite($Y & @CR)
ConsoleWrite(($X = $Y) & @CR)
ConsoleWrite((_Precise($X) = _Precise($Y)) & @CR)

Func _Precise($Value)
	Return Round($Value, 15)
EndFunc   ;==>_Precise
 

kaster

Мой Аватар, он лучший самый
Команда форума
Глобальный модератор
Сообщения
4 020
Репутация
622
а в чем проблема? в последней единичке на энном знаке, или в том, что счет идет до .99 вместо 1?
 
Автор
Yashied

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5 379
Репутация
2 711
Kaster сказал(а):
а в чем проблема? в последней единичке на энном знаке, или в том, что счет идет до .99 вместо 1?
Одно связано с другим.
 

kaster

Мой Аватар, он лучший самый
Команда форума
Глобальный модератор
Сообщения
4 020
Репутация
622
мда. действительно. ерунда какая-то. никогда не задумывался


Добавлено:
Сообщение автоматически объединено:

удивительно, но код на питоне выдает аналогичный результат
Код:
i = 0.0
while i<=1.0:
	print(str(i) + "\t" + str(i == 1.0))
	i += .01
 

SyDr

Сидра
Сообщения
651
Репутация
158
Ну... Вообще-то при сравнении целых чисел с вещественными, последнии необходимо окргулять с нужной точностью. Об этом обычно говорят. Просто, что в AutoIt использование различных типов данных для пользователей прозрачно.
Поведение в Паскале точно такое же.
 

kaster

Мой Аватар, он лучший самый
Команда форума
Глобальный модератор
Сообщения
4 020
Репутация
622
SyDr
а при сравнении вещественных чисел с вещественными? :smile: потому как во втором коде проводится именно такое сравнение
 

SyDr

Сидра
Сообщения
651
Репутация
158
М... Неправильно написал. Дело не в том, что с чем с сравнивать, а в том, что при работе с вещественными числами неизбежно возникают такие погрешности. Последней цифре мантиссы вообще нельзя доверять. И это нормально.
 
Автор
Yashied

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5 379
Репутация
2 711
Не могу проверить сейчас на Паскале, но раньше таких проблем не возникало, это абсолютно точно. Более того, в Паскале (Turbo Pascal) было несколько типов для вещественных чисел. Если мне не изменяет память, то тип Extended был самым точным...
 

SyDr

Сидра
Сообщения
651
Репутация
158
Да, с extended именно этой конкретной проблемы не возникает. Но этот тип не только точнее, но и медленнее и использует больше памяти. И в AutoIt его нету :smile:
Просто число 0.01 в двоичке - переодическая дробь. Все "лишнии" знаки обрезаются. От этого никуда не деться.
 
Автор
Yashied

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5 379
Репутация
2 711

kaster

Мой Аватар, он лучший самый
Команда форума
Глобальный модератор
Сообщения
4 020
Репутация
622

SyDr

Сидра
Сообщения
651
Репутация
158
Очень низкое число операций :smile: Такое ощущение, что переменная хранит информации больше, чем показывает :(

Если увеличить число операций, то всё это опять вылезет. Самое интересное, что число может быть сначала вида: ...999999, а потом ...000001, 000002 и т.д.


В качестве обмана можно использовать числа кратные двум. В двоичке они конечные и не переодичские: 0.5, 0.25, 0.125 и т.д.


Добавлено:
Сообщение автоматически объединено:

Всё таки я тпулю щас немного. Вот, здесь можно нормально почитать по этому поводу:
http://pco.iis.nsk.su/ICP/Introduction/dd2/node7.html

Следует иметь в виду, что арифметические операции, применимые к значениям типа real, выполняются неточно (с округлением результата до ближайщего числа из real) и тем самым отличаются от соответствующих математических операций. Здесь (так же как и для типа Integer) возможно переполнение -- выход результата за границы диапазона представимых чисел. Помимо этого возникает ряд эффектов, связанных с округлением -- например, при вычитании двух почти равных значений результатом является нулевое значение (это явление называется сокращением или потерей значимости).
 
Автор
Yashied

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5 379
Репутация
2 711
SyDr [?]
В качестве обмана можно использовать числа кратные двум.
... или использовать функцию с красивым названием _Precise(). Она меня пока еще ни разу не подводила.

:smile:
 
Верх