Bitwise và thay cho toán tử mô-đun


91

Chúng tôi biết rằng ví dụ mô-đun quyền lực của hai có thể được biểu thị như sau:

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

Ví dụ:

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

Điều gì về phi sức mạnh chung của hai số?

Hãy cùng nói nào:

x% 7 ==?


8
@Neil - Modulo và Binary Và là những hoạt động khá cơ bản, tôi đoán chúng giống nhau trong bất kỳ ngôn ngữ máy tính nào.
James Kolpack

1
Tôi làm được một chút mệt mỏi của không nhìn thấy ngôn ngữ posted :) Mặc dù tôi đoán thường nếu họ không chỉ định, tôi cho rằng phương tiện C ++ hoặc C. Tôi ngạc nhiên như thế nào đúng là là ..
Garet Claborn

1
Chỉ dành cho những ai đang gặp khó khăn trong việc hiểu điều này, hãy xem stackoverflow.com/a/13784820/1414639 . Ồ, và trong JS với V8, tôi được tăng hiệu suất rất nhẹ bằng cách sử dụng các toán tử bitwise.
Bardi Harborow

1
@JamesKolpack Một thao tác bitwise có thể được thực hiện trên CPU nhanh hơn NHIỀU so với mô-đun. Trong thực tế, một thủ thuật lắp ráp phổ biến để không một thanh ghi là XOR nó với chính nó (vì thực tế này). Ngày nay, một trình biên dịch có thể tối ưu hóa mô-đun của lũy thừa hai, nhưng tôi không biết
Kaiser Keister

Câu trả lời:


70

Trước hết, thực sự không chính xác khi nói rằng

x % 2 == x & 1

Phản ví dụ đơn giản: x = -1. Trong nhiều ngôn ngữ, bao gồm cả Java -1 % 2 == -1,. Đó %không nhất thiết là định nghĩa toán học truyền thống của modulo. Ví dụ, Java gọi nó là "toán tử phần dư".

Liên quan đến tối ưu hóa bitwise, chỉ lũy thừa mô-đun của hai có thể "dễ dàng" được thực hiện trong số học bit. Nói chung, chỉ lũy thừa môđun của cơ số b có thể "dễ dàng" được thực hiện với biểu diễn cơ số b của các số.

Ví dụ, trong cơ số 10, đối với không âm N, N mod 10^kchỉ lấy các kchữ số có nghĩa nhỏ nhất .

Người giới thiệu


1
-1 = -1 (mod 2), không chắc bạn đang nhận được gì - ý bạn là nó không giống với phần còn lại của IEEE 754?
BlueRaja - Danny Pflughoeft

2
@BlueRaja: dư lượng chung cho -1 trong mod 2 là 1 en.wikipedia.org/wiki/Modular_arithmetic#Remainders
polygenelubricants

@BlueRaja: Nếu bạn cho phép số âm, điều bạn có thể chắc chắn về cơ bản (đặc biệt vì không có ngôn ngữ nào được đề cập) là (a / b) / b + a % b == ađối với toán tử kiểu C, số nguyên a và b, b khác không, và cả abs(a % b) < abs(b)với cùng điều kiện.
David Thornley

1
@DavidThornley - giả sử ý bạn là (a / b)* b + a % b == a.
sfjac

40

Chỉ có một cách đơn giản để tìm modulo của 2 ^ i số bằng cách sử dụng bitwise.

Có một cách khéo léo để giải quyết các trường hợp Mersenne theo liên kết chẳng hạn như n% 3, n% 7 ... Có những trường hợp đặc biệt cho n% 5, n% 255, và các trường hợp tổng hợp như n% 6.

Đối với trường hợp 2 ^ i, (2, 4, 8, 16 ...)

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

Những cái phức tạp hơn rất khó giải thích. Chỉ đọc nếu bạn rất tò mò.


1
bình chọn ++; Liên kết tuyệt vời, cảm ơn đã tham khảo. Tôi khuyên những người khác hãy xem qua, nó rất đáng đọc cho dù nó hơi phức tạp.
varzeak

liên kết là phần tốt nhất của câu trả lời.
Amit Kumar

n% 2 ^ i = n & (1 << i - 1)
Kartik Singh

18

Điều này chỉ hoạt động đối với lũy thừa của hai (và thường chỉ là số dương) vì chúng có đặc tính duy nhất là chỉ có một bit được đặt thành '1' trong biểu diễn nhị phân của chúng. Bởi vì không có lớp số nào khác chia sẻ thuộc tính này, bạn không thể tạo biểu thức bit-và cho hầu hết các biểu thức mô-đun.


2
Nếu bạn tình cờ hoạt động trên một kiến ​​trúc bậc ba, thì điều đó sẽ thay đổi một chút ... tuy nhiên, rất có thể là con số không.
Noldorin

Tôi thích cách bạn diễn đạt nó: "điều đó thay đổi một chút "
j3141592653589793238

12

Đây đặc biệt là một trường hợp đặc biệt vì máy tính biểu diễn các số trong cơ số 2. Điều này có thể khái quát được:

(số) cơ sở % cơ sở x

tương đương với x chữ số cuối cùng của (số) cơ số .


5

Có các moduli khác với lũy thừa của 2 mà các thuật toán hiệu quả tồn tại.

Ví dụ: nếu x là 32 bit không dấu int thì x% 3 = popcnt (x & 0x55555555) - popcnt (x & 0xaaaaaaaa)


4

Modulo "7" không có toán tử "%"

int a = x % 7;

int a = (x + x / 7) & 7;

3
Không hoạt động cho 10% 2 = 0. (10 + 10/2) & 2 = 15 & 2 = 2, Tương tự 10% 6 = 4. (10 + 10/6) & 6 = 11 & 6 = 2
Sriram Murali

10
Ngoài ra, tại sao bạn muốn phân chia khi bạn muốn tránh sử dụng modulo? AFAIK, lệnh chia giống như lệnh lấy phần dư.
Horse SMith

2
@SriramMurali Đó là bởi vì bạn đã sử dụng một mod chẵn, tất nhiên nó sẽ không hoạt động, đây là một cách giải quyết cho lẻ như OP đã nói.
ylun.ca

3

Không sử dụng toán tử bitwise-and ( &) trong nhị phân, không có. Phác thảo bằng chứng:

Giả sử có một giá trị k sao cho x & k == x % (k + 1), nhưng k! = 2 ^ n - 1 . Sau đó, nếu x == k , biểu thức x & kdường như "hoạt động chính xác" và kết quả là k . Bây giờ, hãy xem xét x == ki : nếu có bất kỳ bit "0" nào trong k , thì sẽ có một số i lớn hơn 0 mà ki chỉ có thể được biểu thị bằng bit 1 ở các vị trí đó. (Ví dụ: 1011 (11) phải trở thành 0111 (7) khi 100 (4) bị trừ khỏi nó, trong trường hợp này, bit 000 trở thành 100 khi i = 4. ) Nếu một bit từ biểu thức của k phải thay đổi từ 0 đến một người để đại diện cho ki, thì nó không thể tính toán chính xác x% (k + 1) , trong trường hợp này phải là ki , nhưng không có cách nào cho boolean bitwise và tạo ra giá trị đó cho mặt nạ.


2

Trong trường hợp cụ thể này (mod 7), chúng tôi vẫn có thể thay thế% 7 bằng các toán tử bitwise:

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

Nó hoạt động vì 8% 7 = 1. Rõ ràng, mã này có thể kém hiệu quả hơn một x% 7 đơn giản và chắc chắn là ít dễ đọc hơn.


1

Sử dụng bitwise_and, bitwise_or và bitwise_not, bạn có thể sửa đổi bất kỳ cấu hình bit nào thành cấu hình bit khác (nghĩa là tập hợp các toán tử này "hoàn chỉnh về mặt chức năng"). Tuy nhiên, đối với các hoạt động như modulus, công thức chung nhất thiết sẽ khá phức tạp, tôi thậm chí sẽ không bận tâm đến việc tạo lại nó.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.