Bitwise dan menggantikan operator modulus

91

Kita tahu bahwa misalnya modulo kekuatan dua dapat diekspresikan seperti ini:

  x % 2 inpower n == x & (2 inpower n - 1).

Contoh:

x % 2 == x & 1
x % 4 == x & 3
x % 8 == x & 7 

Bagaimana dengan nonpower umum dari dua angka?

Katakanlah:

x% 7 ==?

dato datuashvili
sumber
8
@Neil - Modulo dan Biner Dan operasi yang cukup mendasar, saya rasa mereka hampir sama dalam bahasa komputer manapun.
James Kolpack
1
Saya sedikit lelah karena tidak melihat bahasa yang diposting :) Meskipun saya kira biasanya jika mereka tidak menentukan, saya berasumsi bahwa itu berarti C ++ atau C. Saya bertanya-tanya seberapa benar itu ..
Garet Claborn
1
Hanya bagi siapa saja yang kesulitan memahami ini, lihat stackoverflow.com/a/13784820/1414639 . Oh, dan di JS dengan V8 saya mendapatkan peningkatan kinerja yang sangat sedikit dengan menggunakan operator bitwise.
Bardi Harborow
1
@JamesKolpack Operasi bitwise dapat dilakukan JAUH lebih cepat pada CPU daripada modulo. Faktanya, trik perakitan umum ke nol register adalah XOR dengan dirinya sendiri (karena fakta ini). Saat ini kompiler mungkin dapat mengoptimalkan modulo dengan kekuatan dua, tetapi saya tidak tahu
Kaiser Keister

Jawaban:

70

Pertama-tama, sebenarnya tidak tepat untuk mengatakannya

x % 2 == x & 1

Counterexample sederhana: x = -1. Dalam banyak bahasa, termasuk Java -1 % 2 == -1,. Artinya, %belum tentu definisi matematika tradisional dari modulo. Java menyebutnya "operator sisa", misalnya.

Berkenaan dengan pengoptimalan bitwise, hanya dua kekuatan modulo yang dapat "dengan mudah" dilakukan dalam aritmatika bitwise. Secara umum, hanya kekuatan modulo dari basis b yang dapat "dengan mudah" dilakukan dengan representasi angka basis b .

Dalam basis 10, misalnya, untuk non-negatif N, N mod 10^khanya mengambil angka paling signifikan k.

Referensi

poligenelubricants
sumber
1
-1 = -1 (mod 2), tidak yakin apa yang Anda maksud - maksud Anda itu tidak sama dengan sisa IEEE 754?
BlueRaja - Danny Pflughoeft
2
@BlueRaja: residu umum untuk -1 dalam mod 2 adalah 1 en.wikipedia.org/wiki/Modular_arithmetic#Remainders
polygenelubricants
@BlueRaja: Jika Anda mengizinkan angka negatif, pada dasarnya Anda bisa yakin (terutama karena tidak ada bahasa yang disebutkan) adalah bahwa (a / b) / b + a % b == a, untuk operator tipe C, bilangan bulat a dan b, b bukan nol, dan juga abs(a % b) < abs(b)dengan ketentuan yang sama.
David Thornley
1
@DavidThornley - anggap maksud Anda (a / b)* b + a % b == a.
sfjak
40

Hanya ada cara sederhana untuk menemukan modulo bilangan 2 ^ i menggunakan bitwise.

Ada cara cerdik untuk menyelesaikan kasus Mersenne sesuai dengan tautan seperti n% 3, n% 7 ... Ada kasus khusus untuk n% 5, n% 255, dan kasus komposit seperti n% 6.

Untuk kasus 2 ^ i, (2, 4, 8, 16 ...)

n % 2^i = n & (2^i - 1)

Yang lebih rumit sulit dijelaskan. Bacalah hanya jika Anda sangat penasaran.

Sriram Murali
sumber
1
memilih ++; Tautan luar biasa, terima kasih atas referensinya. Saya menyarankan orang lain untuk melihatnya, ini layak dibaca meskipun agak rumit.
varzeak
tautan adalah bagian terbaik dari jawabannya.
Amit Kumar
n% 2 ^ i = n & (1 << i - 1)
Kartik Singh
18

Ini hanya berfungsi untuk pangkat dua (dan seringkali hanya yang positif) karena mereka memiliki properti unik yang hanya memiliki satu bit yang disetel ke '1' dalam representasi binernya. Karena tidak ada kelas bilangan lain yang berbagi properti ini, Anda tidak dapat membuat bitwise-dan ekspresi untuk sebagian besar ekspresi modulus.

VeeArr
sumber
2
Jika Anda kebetulan beroperasi pada arsitektur terner, maka hal itu mengubah sedikit ... kemungkinannya nol.
Noldorin
Saya suka bagaimana Anda mengucapkannya: "yang mengubah sedikit "
j3141592653589793238
12

Ini secara khusus merupakan kasus khusus karena komputer mewakili angka di basis 2. Ini dapat digeneralisasikan:

(angka) basis % basis x

setara dengan digit x terakhir dari (bilangan) basis .

jdmichal.dll
sumber
5

Ada modulus selain pangkat 2 yang memiliki algoritme efisien.

Misalnya, jika x adalah 32 bit unsigned int maka x% 3 = popcnt (x & 0x55555555) - popcnt (x & 0xaaaaaaaa)

David Harris
sumber
4

Modulo "7" tanpa operator "%"

int a = x % 7;

int a = (x + x / 7) & 7;
ashuwp.dll
sumber
3
Tidak bekerja selama 10% 2 = 0. (10 + 10/2) & 2 = 15 & 2 = 2, Demikian pula 10% 6 = 4. (10 + 10/6) & 6 = 11 & 6 = 2
Sriram Murali
10
Juga, mengapa Anda ingin membagi ketika Anda ingin menghindari penggunaan modulo? AFAIK, instruksi untuk membagi sama dengan instruksi untuk mendapatkan sisanya.
Horse SMith
2
@SriramMurali Itu karena Anda menggunakan mod genap, tentu saja itu tidak akan berhasil, ini adalah solusi untuk yang aneh seperti kata OP.
ylun.ca
3

Tidak menggunakan bitwise-dan (& operator ) dalam biner, tidak ada. Sketsa bukti:

Misalkan ada nilai k sedemikian rupa x & k == x % (k + 1), tetapi k! = 2 ^ n - 1 . Kemudian jika x == k , pernyataan tersebut x & ktampaknya "beroperasi dengan benar" dan hasilnya adalah k . Sekarang, pertimbangkan x == ki : jika ada bit "0" di k , ada beberapa i lebih besar dari 0 yang ki hanya dapat diekspresikan dengan 1-bit pada posisi tersebut. (Misalnya, 1011 (11) harus menjadi 0111 (7) ketika 100 (4) telah dikurangi darinya, dalam hal ini 000 bit menjadi 100 ketika i = 4. ) Jika sedikit dari ekspresi k harus berubah dari nol ke satu untuk mewakili ki, maka itu tidak dapat menghitung dengan benar x% (k + 1) , yang dalam hal ini seharusnya ki , tetapi tidak ada cara untuk bitwise boolean dan untuk menghasilkan nilai tersebut dengan menggunakan mask.

Heath Hunnicutt
sumber
2

Dalam kasus khusus ini (mod 7), kami masih dapat mengganti% 7 dengan operator bitwise:

// Return X%7 for X >= 0.
int mod7(int x)
{
  while (x > 7) x = (x&7) + (x>>3);
  return (x == 7)?0:x;
}

Ia bekerja karena 8% 7 = 1. Jelas, kode ini mungkin kurang efisien daripada x% 7 sederhana, dan tentunya kurang dapat dibaca.

Eric Bainville
sumber
1

Dengan menggunakan bitwise_and, bitwise_or, dan bitwise_not Anda dapat mengubah konfigurasi bit apa pun ke konfigurasi bit lain (yaitu, rangkaian operator ini "berfungsi lengkap"). Namun, untuk operasi seperti modulus, rumus umum akan menjadi sangat rumit, saya bahkan tidak akan repot-repot mencoba membuatnya kembali.

Lie Ryan
sumber