Что нового

Переполнение в операциях с вещественными числами

Yashied

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

Код:
$A = 1
$B = 0
$R = $A / $B

ConsoleWrite($R & @CR)


Можно конечно воспользоваться StringInStr($R, '#'), но это сильно снизит скорость расчетов, что не есть хорошо.
 

SyDr

Сидра
Сообщения
651
Репутация
158
IsNumber подходит?

А вообще, для мат. расчётов AutoIt плохо подходит. У меня код на Паскале и AutoIt, решающий одну задачку. На AutoIt работал полчаса. Тоже самое на Паскале - около 6 секунд.
 

kaster

Мой Аватар, он лучший самый
Команда форума
Глобальный модератор
Сообщения
4 020
Репутация
622
SyDr [?]
1.#INF - это тоже число
Код:
$a = 1
$b = 0
$c = $a / $b
MsgBox(0, '', IsNumber($c))



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

Как вариант могу предложить сравнивать бесконечность с бесконечностью - 1.
ниже код для среднего времени выполнения сравнений при прочих равных при 100000 испытаниях - один для нахождения символа "#" в числе, другой сравнение Inf = Inf - 1. На моей машине разница получается примерно 1.5 раза
Код:
$a = 1
$b = 0
$c = $a / $b
$elaps1 = 0
$elaps2 = 0
$rel = 0
$N = 100000
For $i = 1 to  $N
	$start = TimerInit()
	If StringInStr($c, '#') Then $buf = 1
	$end = TimerDiff($start)
	$elaps1 += $end
	$start = TimerInit()
	If ($c - 1 = $c) Then $buf = 1
	$end = TimerDiff($start)
	$elaps2 +=  $end
	$rel += $elaps1 / $elaps2
Next
MsgBox(0, 'Elapsed times', 'Average time elapsed for string compare is ' & $elaps1 / $N & ' msecs' & @CRLF & _ 
'Average time elapsed for infinity compare is ' & $elaps2 / $N & ' msecs' & @CRLF & _
'Ratio is ' & $rel / $N)

Может пригодится
 
Автор
Yashied

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5 379
Репутация
2 702
Я это уже проделывал, у меня тоже ~2x. У меня количество обращений может доходить до 1 млн. с соответствующими последствиями. Поэтому StringInStr() я сразу откинул. Второй вариант тоже пробывал, и здесь есть засада:

Код:
$A = ACos(2)
$B = 0/0

ConsoleWrite($A & @CR)
ConsoleWrite($B & @CR)
ConsoleWrite(($A = $B) & @CR)


Сейчас делаю так:

Код:
Global Const $NaN = Abs(Int(0/0))

ConsoleWrite(_IsOverflow(0/0) & @CR)
ConsoleWrite(_IsOverflow(1/0) & @CR)
ConsoleWrite(_IsOverflow(Sqrt(-1)) & @CR)
ConsoleWrite(_IsOverflow(ACos(2)) & @CR)

Func _IsOverflow($Value)
    If Abs(Int($Value)) = $NaN Then
        Return 1
    Else
        Return 0
    EndIf
EndFunc   ;==>_IsOverflow
 

kaster

Мой Аватар, он лучший самый
Команда форума
Глобальный модератор
Сообщения
4 020
Репутация
622
Yashied [?]
и здесь есть засада:
а в чем есть засада? я так понял ты хочешь проверить переполнился ли стэк для конкретно данного числа. поэтому надо сравнивать его с самим же.
а по поводу второй проверки, моя тачка показывает мне что такое сравнение на 15% хуже сравнения числа с самим собой
Код:
$a = 1
$b = 0
$c = $a / $b
$elaps1 = 0
$elaps2 = 0
$elaps3 = 0
$rel = 0
$N = 100000
For $i = 1 to  $N
    $start = TimerInit()
    If StringInStr($c, '#') Then $buf = 1
    $end = TimerDiff($start)
    $elaps1 += $end
    $start = TimerInit()
    If ($c - 1 = $c) Then $buf = 1
    $end = TimerDiff($start)
    $elaps2 +=  $end
    $start = TimerInit()
    If Abs(Int($c)) > 9.22337203685477e+018 Then $buf = 1
    $end = TimerDiff($start)
    $elaps3 += $end
	$rel += 100 * ($elaps3 - $elaps2) / $elaps2
Next
MsgBox(0, 'Elapsed times', 'Average time elapsed for string compare is ' & $elaps1 / $N & ' msecs' & @CRLF & _
'Average time elapsed for infinity compare is ' & $elaps2 / $N & ' msecs' & @CRLF & _
'Average time elapsed for infinity compare is ' & $elaps3 / $N & ' msecs' & @CRLF & _
'Ratio is ' & $rel / $N)



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

и еще, 0/0, sqrt(-1) и acos(2) - Это не переполнение. если autoit не отличается от других языков, то это неопределенность. просто отдельный класс чисел. но под сравнение Ind = Ind - 1 подходит вполне сносно
 
Автор
Yashied

Yashied

Модератор
Команда форума
Глобальный модератор
Сообщения
5 379
Репутация
2 702
Kaster сказал(а):
...а в чем есть засада?
Код:
$a = 0
$b = 0
$c = $a / $b

ConsoleWrite($c & @CR)

If ($c - 1 = $c) Then
	MsgBox(0, '', 'OK')
	$buf = 1
EndIf
 

kaster

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


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

Какого рода операции? Если их кол-во ограничено то можно вручную отслеживать передачу аргументов функциям генерируя исключения.
 

amel27

Продвинутый
Сообщения
146
Репутация
55
строго говоря, нужно над результатом провести обратное действие и сравнить с исходным числом (циклическое преобразование) - только при совпадении можно быть уверенным в отсутствии переполнения, как вариант могу предложить трикс (аналогичный), пока на текущей версии прокатывает:

Код:
$A = 1
$B = 0
$R = $A / $B

If $R-$R=0 Then
	ConsoleWrite($R & @CRLF)
Else
	ConsoleWrite("ERR: Переполнение!" & @CRLF)
EndIf
 

kaster

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

Yashied

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