Что нового

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

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5,379
Репутация
2,724
Есть в 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
Репутация
626
а в чем проблема? в последней единичке на энном знаке, или в том, что счет идет до .99 вместо 1?
 
Автор
Yashied

Yashied

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

Одно связано с другим.
 

kaster

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


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

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

SyDr

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

kaster

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

SyDr

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

Yashied

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

SyDr

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

kaster

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

SyDr

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

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


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


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

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

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

Yashied

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

... или использовать функцию с красивым названием _Precise(). Она меня пока еще ни разу не подводила.

:smile:
 
Верх