11.11.2015 Взять и поделить или деление по модулю
Korogodin (обсуждение | вклад) |
Korogodin (обсуждение | вклад) |
||
Строка 18: | Строка 18: | ||
:'''[c*(a+b)]mod n = [c*a(mod n) + c*b(mod n)]mod n''' | :'''[c*(a+b)]mod n = [c*a(mod n) + c*b(mod n)]mod n''' | ||
− | Как оказалось, следует отличать понятия '''остатка от деления (remainder after devision)'''<ref>[https://ru.wikipedia.org/wiki/Деление_с_остатком Wiki: Деление с остатком]</ref> и '''приведения числа по модулю (modulus after devision)''', т.к. в первом случае число приводится к диапазону [0 |b|]. | + | Как оказалось, следует отличать понятия '''остатка от деления (remainder after devision)'''<ref>[https://ru.wikipedia.org/wiki/Деление_с_остатком Wiki: Деление с остатком]</ref><ref>[https://en.wikipedia.org/wiki/Modulo_operation Wiki: Modulo operation]</ref> и '''приведения числа по модулю (modulus after devision)''', т.к. в первом случае число приводится к диапазону [0 |b|]. |
Так какие функции и операторы реализуют остаток от деления, какие взятие по модулю, и как они зависят от типов аргументов? Ниже представлены результаты, полученные на Oryx 161, компилятор из Xilinx SDK 2014.4 ( gcc version 4.8.3 20140320 (prerelease) (Sourcery CodeBench Lite 2014.05-23)). | Так какие функции и операторы реализуют остаток от деления, какие взятие по модулю, и как они зависят от типов аргументов? Ниже представлены результаты, полученные на Oryx 161, компилятор из Xilinx SDK 2014.4 ( gcc version 4.8.3 20140320 (prerelease) (Sourcery CodeBench Lite 2014.05-23)). | ||
Строка 73: | Строка 73: | ||
* int a % int b ведет себя как функция mod() в MATLAB только при совпадении знаков аргументов, иначе есть смещение на b (за исключением точек, в которых результат ноль) | * int a % int b ведет себя как функция mod() в MATLAB только при совпадении знаков аргументов, иначе есть смещение на b (за исключением точек, в которых результат ноль) | ||
+ | <!--- | ||
'''Выводы''': | '''Выводы''': | ||
* Остаток от деления и операция взятия по модулю не совпадают при аргументах с разными знаками | * Остаток от деления и операция взятия по модулю не совпадают при аргументах с разными знаками | ||
* Оператор % дает остаток от деления | * Оператор % дает остаток от деления | ||
+ | --> | ||
Для наглядности построены графики (доступен fig): | Для наглядности построены графики (доступен fig): |
Версия 13:47, 12 ноября 2015
|
Есть некоторая неуверенность в результатах работы функций взятия модуля, для борьбы с которой составлена эта памятка.
Лично я привык к работе функции mod(a, b) в MATLAB, которая приводит a к диапазону [0 b] или [b 0] (в зависимости от знака b) путем прибавления/вычитания целого числа b к/из a. Что выражается в формуле:
- mod(a, b) = a - floor(a ./ b)*b,
где функция floor - округление в сторону минус бесконечности.
Операция взятия остатка по модулю замечательна своими свойствами:
- (a+b)mod n = [a(mod n) + b(mod n)]mod n
- (a-b)mod n = [a(mod n) - b(mod n)]mod n
- (a*b)mod n = [a(mod n) * b(mod n)]mod n
- [c*(a+b)]mod n = [c*a(mod n) + c*b(mod n)]mod n
Как оказалось, следует отличать понятия остатка от деления (remainder after devision)[1][2] и приведения числа по модулю (modulus after devision), т.к. в первом случае число приводится к диапазону [0 |b|].
Так какие функции и операторы реализуют остаток от деления, какие взятие по модулю, и как они зависят от типов аргументов? Ниже представлены результаты, полученные на Oryx 161, компилятор из Xilinx SDK 2014.4 ( gcc version 4.8.3 20140320 (prerelease) (Sourcery CodeBench Lite 2014.05-23)).
Классический %
(int(13)) % (int(-7)) = 6
(int(13)) % (int(-5)) = 3
(int(13)) % (int(-1)) = 0
(int(13)) % (int(1)) = 0
(int(13)) % (int(5)) = 3
(int(13)) % (int(7)) = 6
(int(13)) % (int(17)) = 13
(int(-13)) % (int(-17)) = -13
(int(-13)) % (int(-7)) = -6
(int(-13)) % (int(-5)) = -3
(int(-13)) % (int(-1)) = 0
(int(-13)) % (int(1)) = 0
(int(-13)) % (int(5)) = -3
(int(-13)) % (int(7)) = -6
(int(-13)) % (int(17)) = -13
(unsigned int(13)) % (int(-17)) = 13
(unsigned int(13)) % (int(-7)) = 13
(unsigned int(13)) % (int(-5)) = 13
(unsigned int(13)) % (int(-1)) = 13
(unsigned int(13)) % (int(1)) = 0
(unsigned int(13)) % (int(5)) = 3
(unsigned int(13)) % (int(7)) = 6
(unsigned int(13)) % (int(17)) = 13
(int(13)) % (unsigned int(1)) = 0
(int(13)) % (unsigned int(5)) = 3
(int(13)) % (unsigned int(7)) = 6
(int(13)) % (unsigned int(17)) = 13
(int(-13)) % (unsigned int(1)) = 0
(int(-13)) % (unsigned int(5)) = 3
(int(-13)) % (unsigned int(7)) = 5
(int(-13)) % (unsigned int(17)) = 5
(unsigned int(13)) % (unsigned int(1)) = 0
(unsigned int(13)) % (unsigned int(5)) = 3
(unsigned int(13)) % (unsigned int(7)) = 6
(unsigned int(13)) % (unsigned int(17)) = 13
Следует обратить внимание:
- int a % uint b = mod(*(uint*(&a)), b) - результаты для -13%(int 7) и -13%(uint 7) различаются; если брать int % uint, то int интерпретируется как uint, например, -1 превращается в 2^32-1.
- uint a % int b = b<0 ? a : mod(a, b) - взятие uint % отрицательного числа - холостая операция, результат - исходный uint
- int a % int b = sign(a) * mod(|a|, |b|) - знак базы игнорируется, что противоречит интуитивному пониманию и mod в MATLAB
- int a % int b = (MATLAB)rem(a, b) - ведет себя как функция rem() в MATLAB: rem(a, b) = a - fix(a/b)*b, где fix() - функция округления в сторону нуля
- int a % int b ведет себя как функция mod() в MATLAB только при совпадении знаков аргументов, иначе есть смещение на b (за исключением точек, в которых результат ноль)
Для наглядности построены графики (доступен fig):
[ Хронологический вид ]Комментарии
Войдите, чтобы комментировать.