Что нового

[Математика] Проблема с IsInt() и Mod()

Sαuron

Новичок
Сообщения
45
Репутация
1
Возникла необходимость проверять число на кратность 0.05 и в программе появились чудные ошибки... Решил разобраться и оказалось, что дело в элементарных функциях Mod() IsInt(), начал их тестировать...
Код:
mod(5.05, 0.05)

Т.е. в этом случае функция mod() должна вернуть 0, но я удивился, когда функция вернула 0.0499999999999995 - с чего это вдруг!? 5.05 делится на 0.05 идеально и без остатка! Очень не люблю я такое, когда очевидный ответ должен быть, но простецкая функция по непонятной причине возвращает полный бред... Недолго думая, я решил сделать аналог через IsInt()...
Код:
isint(5.05 / 0.05)

И что же... Функция isint() возвращает 0! Серьезно?! 5.05 / 0.05 = 101 и это дробь!? Это целое число и функция обязана вернуть 1!
Почему так происходит? Я с такими глюками скоро сума сойду!
 
Автор
S

Sαuron

Новичок
Сообщения
45
Репутация
1
Я, конечно, могу сделать рабочий аналог функции isint, типа:
Код:
msgbox(64, '', _isint(5.05 / 0.05))
func _isint($p_1)
   if stringinstr(string($p_1), '.') then
	  return 0
   else
	  return 1
   endif
endfunc

НО! Эта функция многократно вызывается в цикле, который подбирает цепочку оффсетов и за свою работу считывает 4 миллиона адресов! Поэтому для меня экономия каждой MS очень важна! И я очень хочу, чтоб встроенная, написанная на СИ, функция Mod() или IsInt() заработала!

P.S.
Хитрость типа приведения к целым числам помогает, но тратится время умножения на 100 и в случае с isint умножать на 100 просто глупо, т.к. если число было дробным станет целым.
Код:
mod(5.05 * 100, 0.05 * 100)



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

Alofa

Гость
OffTopic:
Вот сколько маломальски на форуме, обратил внимание: частенько бывают "наплывы" тем примерно одной тематики. Не было, не было - и вдруг все заинтересовались.

Вот тема: Autoit разучился считать?

Да и в описании функции Mod():
Эта функция не гарантирует достоверный результат, при использовании чисел double и float (с плавающей точкой).

Если в функцию передаются целые числа, то операция выполняется по модулю. Иначе возвращается результат выполненный операцией с плавающей точкой, что означает, как и в вышеуказанном примечании, что операция может не дать ожидаемого результата.


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

А вот тоже из справки, только уже к функции Int():
Int(0/0) возвращает -9223372036854775807, если интересно :).
 
Автор
S

Sαuron

Новичок
Сообщения
45
Репутация
1
Alofa сказал(а):
OffTopic:
Вот сколько маломальски на форуме, обратил внимание: частенько бывают "наплывы" тем примерно одной тематики. Не было, не было - и вдруг все заинтересовались.

Вот тема: Autoit разучился считать?

Да и в описании функции Mod():
Эта функция не гарантирует достоверный результат, при использовании чисел double и float (с плавающей точкой).

Если в функцию передаются целые числа, то операция выполняется по модулю. Иначе возвращается результат выполненный операцией с плавающей точкой, что означает, как и в вышеуказанном примечании, что операция может не дать ожидаемого результата.


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

А вот тоже из справки, только уже к функции Int():
Int(0/0) возвращает -9223372036854775807, если интересно :).




Для представления 0.5 в двоичной системе требуется всего лишь 1 разряд (1 / 2^1), это число не приближенно к 0.5, а точно 0.5. Тут не может быть этой проблемы, как и со всеми числами, которые возможно составить суммой из (1 / 2^ Х) выражений. Эта проблема может быть с числами типа 0.6 тут уже приближенно будет, на сколько разрядности хватит (1 / 2^1) + 0 + 0 + (1 / 2^4) + (1 / 2^5) + (1 / 2^6) + (1 / 2^7) + (1 / 2^8) и т.д. Проблема в чем-то другом, но я уже понял, что ее не решить, придется велосипед изобретать -.-

Я честно говоря не знаю, хотя тут явно в случае mod(5.05, 0.05) деление идет не на 0.05, а на 0.050000000001, откуда этот остаток может взяться в этом числе, ну хоть прибейте не понимаю, разрядность двоичной системы же позволяет представить ну вот 2 ^ (-1) или 1 / 2 ^ 1, так же, как число 0.75 = 2^(-1) + 2^(-2) нет тут никаких погрешностей...

Тут проблема на низком уровне... Может кто-то из знатоков все же просветит? Что не так с этими простейшими действиями mod() isint() ???
 
A

Alofa

Гость
Sαuron сказал(а):
... Проблема в чем-то другом...
Самая большая проблема заключается в самих дробных (не целых) десятичных числах, а точнее в переводе их в двоичную СС и обратно.

Что касается целых чисел, то тут проблемы никакой:
Пример. Перевести число 11(10) в двоичную систему счисления.
Perev1.jpg

... а вот с дробями придется повозиться:
Чтобы перевести правильную дробь из системы счисления с основанием d1 в систему с основанием d2, необходимо последовательно умножать исходную дробь и дробные части получающихся произведений на основание новой системы счисления d2. Правильная дробь числа в новой системе счисления с основанием d2 формируется в виде целых частей получающихся произведений, начиная с первого.

При переводе смешанных чисел, необходимо в новую систему перевести отдельно целую и дробную части по правилам перевода целых чисел и правильных дробей, а затем оба результата объединить в одно смешанное число в новой системе счисления.

Пример. Перевести число 0,625(10) в двоичную систему счисления.
Perev12.jpg
Как мы видим из данного примера, в принципе проблемы-то тоже нет, все получилось четко.
Но так бывает не всегда.
Попробуйте перевести число 0.05(10) в бинарный вид. Получится примерно следующее:
Шаг: Бит: Вычисления:
100.05
* 2
0.1
200.1
* 2
0.2
300.2
* 2
0.4
400.4
* 2
0.8
510.8
* 2
1.6
610.6
* 2
1.2
700.2
* 2
...

Смотрите, исходное значение шага 7 аналогично значению шага 3, а это означает что крайний блок битов [0011] при дальнейшем расчете будет повторяться до бесконечности.
... вот вам и погрешность. Что делает в этом случае ОС? Правильно - обрезает число.

Если при переводе получается дробь в виде бесконечного или расходящегося ряда, процесс можно закончить при достижении необходимой точности.
В нашам случае необходимая точность достигается при
0.05(10) = 0.00001100110011001100110011001100110011001100110011(2)

P.s: цитаты и картинки приведены *Отсюда*.
 
Автор
S

Sαuron

Новичок
Сообщения
45
Репутация
1
Alofa сказал(а):
Sαuron сказал(а):
... Проблема в чем-то другом...
Самая большая проблема заключается в самих дробных (не целых) десятичных числах, а точнее в переводе их в двоичную СС и обратно.

Что касается целых чисел, то тут проблемы никакой:
Пример. Перевести число 11(10) в двоичную систему счисления.
Perev1.jpg

... а вот с дробями придется повозиться:
Чтобы перевести правильную дробь из системы счисления с основанием d1 в систему с основанием d2, необходимо последовательно умножать исходную дробь и дробные части получающихся произведений на основание новой системы счисления d2. Правильная дробь числа в новой системе счисления с основанием d2 формируется в виде целых частей получающихся произведений, начиная с первого.

При переводе смешанных чисел, необходимо в новую систему перевести отдельно целую и дробную части по правилам перевода целых чисел и правильных дробей, а затем оба результата объединить в одно смешанное число в новой системе счисления.

Пример. Перевести число 0,625(10) в двоичную систему счисления.
Perev12.jpg
Как мы видим из данного примера, в принципе проблемы-то тоже нет, все получилось четко.
Но так бывает не всегда.
Попробуйте перевести число 0.05(10) в бинарный вид. Получится примерно следующее:
Шаг: Бит: Вычисления:
100.05
* 2
0.1
200.1
* 2
0.2
300.2
* 2
0.4
400.4
* 2
0.8
510.8
* 2
1.6
610.6
* 2
1.2
700.2
* 2
...

Смотрите, исходное значение шага 7 аналогично значению шага 3, а это означает что крайний блок битов [0011] при дальнейшем расчете будет повторяться до бесконечности.
... вот вам и погрешность. Что делает в этом случае ОС? Правильно - обрезает число.

Если при переводе получается дробь в виде бесконечного или расходящегося ряда, процесс можно закончить при достижении необходимой точности.
В нашам случае необходимая точность достигается при
0.05(10) = 0.00001100110011001100110011001100110011001100110011(2)

P.s: цитаты и картинки приведены *Отсюда*.
Хоспаде, ночью писал, с туманом в голове, естественно 0.05 проблемное число, самое близкое к нему из разрядов двоичной системы это 1 / 2^5 (единица в пятой позиции после точки), а дальше идут 1 в разрядах, которые вмещаются в рамки 0.05 числа, это число я и имел в виду изначально, а я что-то про 0.5 начал писать, мдаа...

Кстати по мне так проще двоичную систему без формул представлять, как (1 * (2 в степени ее позиции, после точки))
 
Верх