Java.util.Random kaynağı satır 294 diyor
if ((n & -n) == n) // i.e., n is a power of 2
// rest of the code
Bu neden?
Java.util.Random kaynağı satır 294 diyor
if ((n & -n) == n) // i.e., n is a power of 2
// rest of the code
Bu neden?
(n & (n - 1)) == 0
ayrıca çalışır (en düşük dereceden biti kaldırır, eğer kalan bit yoksa, o zaman ilk etapta en fazla 1 bit kümesi vardır).
Yanıtlar:
Açıklama tamamen doğru değildir çünkü (0 & -0) == 0
0 ikinin kuvveti değildir. Bunu söylemenin daha iyi bir yolu
((n & -n) == n)
n ikinin bir kuvveti veya ikinin bir kuvvetinin negatifi veya sıfır olduğunda.
Eğer n ikinin bir kuvveti ise, ikilik tabanda n tek bir 1 ve ardından sıfırlardır. -n ikinin tümleyeninde ters + 1'dir, böylece bitler bu şekilde sıralanır
n 0000100...000
-n 1111100...000
n & -n 0000100...000
Bunun neden işe yaradığını görmek için ikinin tümleyenini ters + 1 olarak düşünün, -n == ~n + 1
n 0000100...000
inverse n 1111011...111
+ 1
two's comp 1111100...000
çünkü ikisinin tamamlayıcısını elde etmek için birini eklerken sonuna kadar taşırsınız.
Eğer n, ikinin kuvvetinden başka bir † olsaydı, sonuç biraz eksik olurdu çünkü ikinin tamamlayıcısı, bu taşıma nedeniyle en yüksek bit setine sahip olmayacaktı.
† - veya sıfır veya iki kuvvetinin negatifi ... yukarıda açıklandığı gibi.
(0 & -0) == 0
, bir yukarıda verilen açıklamada ise if (n <= 0) throw ...
. Bu, test edilen sayının o noktada asla 0 (veya negatif) olmayacağı anlamına gelir.
Random.java
.
n
olduğu hakkında hiçbir şey bilmiyoruz ; Bu varsayımı kontrol etmedim, ancak bir şekilde double
a'nın da aynı şekilde davranacağından şüpheliyim .
n
Bu soru "java" etiketine sahip olduğu için türüne oldukça iyi sınırlar koyabiliriz . Java'da veya içinde &
tanımlanmamıştır . Yalnızca tam sayı türlerinde ve mantıksal değerde tanımlanır. Yana boolelerde için tanımlı değil, biz güvenle anlaması olabilir ayrılmaz bir parçasıdır. double
float
-
n
Çünkü 2'nin belirtilen bütünleyici, -n
olduğu ~n+1
.
Eğer n
2 'lik bir güçtür, o zaman sadece bir bit kümesi vardır. Onun ~n
dışındaki tüm bitler de öyle. 1 ekleyin ve özel biti tekrar ayarlayarak n & (that thing)
eşit olmasını sağlayın n
.
Bunun tersi de doğrudur çünkü 0 ve negatif sayılar, o Java kaynağındaki önceki satır tarafından dışlanmıştır. Birden n
fazla bit setine sahipse, bunlardan biri bu tür en yüksek bittir. Bu biraz edecek değil ayarlanabilir +1
bir alt net biraz orada çünkü onu "absorbe":
n: 00001001000
~n: 11110110111
-n: 11110111000 // the first 0 bit "absorbed" the +1
^
|
(n & -n) fails to equal n at this bit.
Bunun neden doğru olduğunu görmek için değerlere bit eşlemler olarak bakmanız gerekir:
1 & 1 = 1
1 & 0 = 0
0 & 1 = 0
0 & 0 = 0
Yani sadece her iki alan da 1 ise 1 çıkacaktır.
Şimdi -n bir 2'nin tamamlayıcısı yapar. Tümünü olarak 0
değiştirir 1
ve 1 ekler.
7 = 00000111
-1 = NEG(7) + 1 = 11111000 + 1 = 11111001
ancak
8 = 00001000
-8 = 11110111 + 1 = 11111000
00001000 (8)
11111000 (-8)
--------- &
00001000 = 8.
Sadece 2'nin kuvvetleri (n & -n)
için n olacaktır .
Bunun nedeni, 2'nin gücünün uzun bir sıfır denizinde tek bir küme biti olarak temsil edilmesidir. Olumsuzlama, 1'lerin denizinde tam tersi, tek bir sıfır (1'in olduğu yerde) verecektir . 1 eklemek, düşük olanları sıfırın olduğu boşluğa kaydıracaktır.
Ve bitsel ve (&) 1'i tekrar filtreleyecektir.
İkinin tümleyen gösteriminde, ikinin üsleri ile ilgili benzersiz olan şey, bunların n = 2 ^ k olduğu k'inci bit haricinde tüm 0 bitlerden oluşmasıdır:
base 2 base 10
000001 = 1
000010 = 2
000100 = 4
...
İkinin tümleyeninde negatif bir değer elde etmek için, tüm bitleri çevirir ve bir eklersiniz. İkinin üsleri için bu, solda pozitif değerde olan 1 bit dahil olmak üzere bir grup 1 ve sonra sağda bir grup 0 elde edeceğiniz anlamına gelir:
n base 2 ~n ~n+1 (-n) n&-n
1 000001 111110 111111 000001
2 000010 111101 111110 000010
4 000100 111011 111100 000100
8 001000 110111 111000 001000
2. ve 4. sütunun sonucunun 2. sütun ile aynı olacağını kolayca görebilirsiniz.
Bu çizelgede eksik olan diğer değerlere bakarsanız, bunun neden ikinin gücü dışında hiçbir şeyi tutmadığını görebilirsiniz:
n base 2 ~n ~n+1 (-n) n&-n
1 000001 111110 111111 000001
2 000010 111101 111110 000010
3 000011 111100 111101 000001
4 000100 111011 111100 000100
5 000101 111010 111011 000001
6 000110 111001 111010 000010
7 000111 111000 111001 000001
8 001000 110111 111000 001000
n & -n (n> 0 için) sadece 1 bit setine sahip olacaktır ve bu bit n'deki en az anlamlı set biti olacaktır. İkinin üssü olan tüm sayılar için, en az anlamlı olan küme biti tek ayarlı bittir. Diğer tüm sayılar için, sonuçta yalnızca en önemsiz olanı ayarlanacak birden fazla bit kümesi vardır.
Bu, 2'nin kuvvetlerinin ve ikisinin tamamlayıcısının özelliği .
Örneğin, 8 al:
8 = 0b00001000
-8 = 0b11111000
İkisinin tamamlayıcısını hesaplamak:
Starting: 0b00001000
Flip bits: 0b11110111 (one's complement)
Add one: 0b11111000
AND 8 : 0b00001000
2'nin katları için, yalnızca bir bit ayarlanacaktır, bu nedenle ekleme , 2 n'nin n'inci bitinin ayarlanmasına neden olacaktır (biri n'inci biti taşımaya devam eder ). Sonra senAND
iki sayıyı aldığınızda, orijinali geri alırsınız.
2'nin üsleri olmayan sayılar için, diğer bitler çevrilmeyecek ve böylece AND
orijinal sayıyı vermeyecektir.
Basitçe, eğer n 2'nin bir üssü ise, bu sadece bir bitin 1'e ayarlandığı ve diğerlerinin 0 olduğu anlamına gelir:
00000...00001 = 2 ^ 0
00000...00010 = 2 ^ 1
00000...00100 = 2 ^ 2
00000...01000 = 2 ^ 3
00000...10000 = 2 ^ 4
and so on ...
ve çünkü -n
2'nin bir tamamlayıcısıdır n
(bu, 1 olan tek bitin olduğu gibi kaldığı ve bu bitin sol tarafındaki bitlerin 1'e oturduğu anlamına gelir ki bu aslında önemli değildir, çünkü AND operatörünün sonucu &
0 olacaktır. iki bitten biri sıfırdır):
000000...000010000...00000 <<< n
&
111111...111110000...00000 <<< -n
--------------------------
000000...000010000...00000 <<< n