Ми знаємо, що, наприклад, модуль потужності двох може бути виражений так:
x % 2 inpower n == x & (2 inpower n - 1).
Приклади:
x % 2 == x & 1
x % 4 == x & 3
x % 8 == x & 7
А як щодо загальної непридатності двох чисел?
Скажімо:
x% 7 ==?
Ми знаємо, що, наприклад, модуль потужності двох може бути виражений так:
x % 2 inpower n == x & (2 inpower n - 1).
Приклади:
x % 2 == x & 1
x % 4 == x & 3
x % 8 == x & 7
А як щодо загальної непридатності двох чисел?
Скажімо:
x% 7 ==?
Відповіді:
Перш за все, це насправді неточно стверджувати
x % 2 == x & 1
Простий контрприклад: x = -1. У багатьох мовах, в тому числі Java, -1 % 2 == -1. Тобто %не обов'язково традиційне математичне визначення модуля. Java, наприклад, називає його "оператором залишку".
Що стосується побітової оптимізації, то в побітовій арифметиці можна "легко" виконати лише модульні ступені двох. Взагалі кажучи, лише модульні степені основи b можна "легко" зробити за допомогою подання чисел бази b .
У підставі 10, наприклад, для неотрицательного N, N mod 10^kпросто приймаючи значущі kцифри.
-1 = -1 (mod 2), не впевнений, на що ви прийшли - ви маєте на увазі, що це не те саме , що залишок IEEE 754?
(a / b) / b + a % b == a, що для операторів типу C a та b цілі числа, b ненульові, а також те, що abs(a % b) < abs(b)з однаковими умовами.
(a / b)* b + a % b == a.
Існує лише простий спосіб знайти модуль 2 ^ і чисел за допомогою побітового розряду.
Існує геніальний спосіб вирішення справ Мерсенна за посиланням, таких як n% 3, n% 7 ... Існують особливі випадки для n% 5, n% 255 та складні випадки, такі як n% 6.
Для випадків 2 ^ i, (2, 4, 8, 16 ...)
n % 2^i = n & (2^i - 1)
Складніші важко пояснити. Читайте, лише якщо вам дуже цікаво.
Це працює лише для степенів двох (і часто лише позитивних), оскільки вони мають унікальну властивість мати лише один біт, встановлений на '1' у своєму двійковому поданні. Оскільки жоден інший клас чисел не ділиться цією властивістю, ви не можете створювати розрядні та вирази для більшості модульних виразів.
Є модулі, крім степенів 2, для яких існують ефективні алгоритми.
Наприклад, якщо x становить 32 біти без підпису int, тоді x% 3 = popcnt (x & 0x55555555) - popcnt (x & 0xaaaaaaaa)
Модуль "7" без оператора "%"
int a = x % 7;
int a = (x + x / 7) & 7;
Не використовуючи побітове та ( &) оператор у двійковому, це не так. Ескіз доказу:
Припустимо, існувало значення k таке, що x & k == x % (k + 1), але k! = 2 ^ n - 1 . Тоді, якщо x == k , вираз, x & kздається, "працює правильно" і результат k . Тепер розглянемо x == ki : якщо в k були будь-які біти "0" , є деяке i більше 0, яке ki може виражатися лише 1-бітами в цих положеннях. (Наприклад, 1011 (11) повинен стати 0111 (7), коли з нього відняли 100 (4), у цьому випадку 000 біт стає 100, коли i = 4. ) Якщо біт із виразу k повинен змінитися з нуля одному представляти кі, тоді він не може правильно обчислити x% (k + 1) , який у цьому випадку повинен бути ki , але побітове логічне значення і отримання цього значення з урахуванням маски не існує.
У цьому конкретному випадку (мод 7) ми все ще можемо замінити% 7 бітовими операторами:
// Return X%7 for X >= 0.
int mod7(int x)
{
while (x > 7) x = (x&7) + (x>>3);
return (x == 7)?0:x;
}
Це працює, оскільки 8% 7 = 1. Очевидно, що цей код, мабуть, менш ефективний, ніж простий x% 7, і, звичайно, менш читабельний.
Використовуючи bitwise_and, bitwise_or і bitwise_not, ви не можете змінити будь-які бітові конфігурації на інші бітові конфігурації (тобто ці набори операторів "функціонально завершені"). Однак для таких операцій, як модуль, загальна формула була б досить складною, я б навіть не намагався її відтворити.