Bitsel ve modül operatörü yerine


91

Örneğin ikinin güç modülünün şu şekilde ifade edilebileceğini biliyoruz:

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

Örnekler:

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

Ya iki sayının genel güçsüzlüğü?

Diyelimki:

x% 7 ==?


8
@Neil - Modulo ve Binary Oldukça temel işlemler, sanırım herhangi bir bilgisayar dilinde aynı.
James Kolpack

1
Gönderilen dili görmemekten biraz yoruldum :) Sanırım genellikle belirtmezlerse, bunun C ++ veya C anlamına geldiğini varsayıyorum. Bunun ne kadar doğru olduğunu merak ediyorum ..
Garet Claborn

1
Bunu anlamakta güçlük çeken herkes için stackoverflow.com/a/13784820/1414639 adresine bir göz atın . Oh, ve V8 ile JS'de bitsel operatörler kullanarak çok hafif bir performans artışı elde ediyorum .
Bardi Harborow

1
@JamesKolpack Bitsel bir işlem, bir CPU üzerinde bir modulodan ÇOK daha hızlı gerçekleştirilebilir. Aslında, bir kaydı sıfırlamak için ortak bir montaj numarası, onu kendisiyle XOR yapmaktır (bu gerçek yüzünden). Günümüzde bir derleyici, ikiye
katlanan bir moduloyu

Yanıtlar:


70

Her şeyden önce, bunu söylemek aslında doğru değil

x % 2 == x & 1

Basit counterexample: x = -1. Java dahil birçok dilde -1 % 2 == -1. Yani, %modulo'nun geleneksel matematiksel tanımı olması gerekmez. Örneğin Java, buna "kalan operatör" diyor.

Bitsel optimizasyonla ilgili olarak, sadece ikinin modulo güçleri bitsel aritmetikte "kolayca" yapılabilir. Genel olarak konuşursak, taban sadece modülo güçler b "kolayca" taban ile yapılabilir b , sayıların gösterimi .

10 tabanı, örneğin olmayan negatif için N, N mod 10^ksadece en az önemli alıyork basamak.

Referanslar


1
-1 = -1 (mod 2), neye ulaştığınızdan emin değilim - IEEE 754'ün geri kalanıyla aynı olmadığınısöylüyorsunuz ?
BlueRaja - Danny Pflughoeft

2
@BlueRaja: mod 2'deki -1 için ortak kalıntı 1'dir en.wikipedia.org/wiki/Modular_arithmetic#Remainders
polygenelubricants

@BlueRaja: Negatif sayılara izin verirseniz, temelde emin olabileceğiniz şey (özellikle hiçbir dilden bahsedilmediği için), (a / b) / b + a % b == aC-tipi operatörler için a ve b tamsayıları, b sıfırdan farklıdır ve ayrıca abs(a % b) < abs(b)aynı koşullarla.
David Thornley

1
@DavidThornley - demek istediğini varsayalım (a / b)* b + a % b == a.
sfjac

40

Bitsel kullanarak 2 ^ i sayılarının modulosunu bulmanın sadece basit bir yolu vardır .

N% 3, n% 7 gibi bağlantıya göre Mersenne vakalarını çözmenin ustaca bir yolu var ... n% 5, n% 255 için özel durumlar ve n% 6 gibi bileşik vakalar var.

2 ^ i durumları için, (2, 4, 8, 16 ...)

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

Daha karmaşık olanları açıklamak zor. Sadece çok merak ediyorsanız okuyun.


1
oy ++; Mükemmel bağlantı, referans için teşekkürler. Başkalarına bir göz atmalarını tavsiye ederim, biraz karmaşık olsa bile okumaya değer.
varzeak

bağlantı cevabın en iyi kısmıdır.
Amit Kumar

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

18

Bu, yalnızca ikisinin (ve genellikle yalnızca pozitif olanların) kuvvetleri için işe yarar çünkü ikili gösterimlerinde yalnızca bir bitin '1'e ayarlanması gibi benzersiz bir özelliğe sahiptirler. Başka hiçbir sayı sınıfı bu özelliği paylaşmadığından, çoğu modül ifadesi için bitsel ve ifadeler oluşturamazsınız.


2
Eğer üçlü bir mimari üzerinde çalışıyorsanız, o zaman bu işleri biraz değiştirir ... ancak şansınız sıfırdır.
Noldorin

Nasıl ifade ettiğinizi beğendim: "bu işleri biraz değiştirir "
j3141592653589793238

12

Bu özellikle özel bir durumdur çünkü bilgisayarlar 2 tabanındaki sayıları temsil eder. Bu genelleştirilebilir:

(sayı) taban % taban x

(sayı) tabanın son x basamağına eşittir .


5

Etkili algoritmaların var olduğu 2'nin üslerinden başka modüller vardır.

Örneğin, x 32 bit işaretsiz int ise x% 3 = popcnt (x & 0x55555555) - popcnt (x & 0xaaaaaaaa)


4

"%" Operatörü olmadan Modulo "7"

int a = x % 7;

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

3
% 10 2 = 0 için çalışmıyor. (10 + 10/2) & 2 = 15 & 2 = 2, Benzer şekilde% 10 6 = 4. (10 + 10/6) & 6 = 11 & 6 = 2
Sriram Murali

10
Ayrıca, modulo kullanmaktan kaçınmak istediğinizde neden bölmek isteyesiniz? AFAIK, bölme talimatı, geri kalanı alma talimatı ile aynıdır.
Horse SMith

2
@SriramMurali Thats, çünkü bir çift mod kullandınız, elbette işe yaramaz, bu, OP'nin dediği gibi garip bir çözüm .
ylun.ca

3

&İkili olarak bitsel ve ( ) operatörünü kullanmamak, yoktur. İspat taslağı:

Diyelim ki öyle bir k değeri var x & k == x % (k + 1), ama k! = 2 ^ n - 1 . O zaman x == k ise, ifade x & k"doğru çalışıyor" gibi görünür ve sonuç k olur . Şimdi, dikkate X == ki : herhangi bir "0" bit olsaydı k , bazı vardır i 0'dan büyük Ki , sadece bu pozisyonlarda 1-bit ile ifade edilebilir. (Örneğin, 1011 (11) ondan 100 (4) çıkarıldığında 0111 (7) olmalıdır, bu durumda i = 4 olduğunda 000 bit 100 olur .) K ifadesinden bir bit ise sıfırdan değişmelidir. ki'yi temsil edecek birine, o zaman bu durumda ki olması gereken x% (k + 1) 'i doğru bir şekilde hesaplayamaz , ancak bitsel boolean ve maske verilen bu değeri üretmenin yolu yoktur.


2

Bu özel durumda (mod 7),% 7'yi bitsel operatörlerle değiştirebiliriz:

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

İşe yarıyor çünkü% 8 7 = 1. Açıktır ki, bu kod muhtemelen basit bir x% 7'den daha az verimli ve kesinlikle daha az okunabilir.


1

Bitwise_and, bitwise_or ve bitwise_not kullanarak herhangi bir bit yapılandırmasını başka bir bit yapılandırmasına değiştirebilirsiniz (yani bu işleçler grubu "işlevsel olarak tamamlanmıştır"). Bununla birlikte, modül gibi işlemler için, genel formül zorunlu olarak oldukça karmaşık olacaktır, onu yeniden oluşturmaya çalışmakla bile uğraşmam.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.