39 bayt almak
Bu, Dennis ve Jonathan Frech'in de ayrı olarak buldukları 39 baytlık bir çözüme nasıl ulaştığımın bir açıklaması . Ya da daha doğrusu, bir kişinin cevaba nasıl ulaşabileceğini, çamurlu muhakeme ve çıkmazlarla dolu olan asıl yolumdan çok daha güzel bir şekilde nasıl açıklanabileceğini açıklar.
n=0
exec"print n;n=n+2^-(n+2^n)%3;"*400
Bunu biraz daha az golf oynayarak ve daha çok parenle yazarken, şöyle görünür:
n=0
for _ in range(400):
print n
n=(n+2)^(-((n+2)^n))%3
Bit pariteleri
Benim bir fikirle başlar 47 bayt çözümü çıkışı formun tüm sayılar için yukarı sayar ve 1'ler bile toplam sayısını kılan bir eşlik biti olduğunu.n=2*k+b
k
0,1,...,399
b
En yazalım par(x)
için biraz parite ait x
xor (olduğunu ^
) biti tümünün x
. Bu, eğer 1 bitlik bir çift varsa (sayı kötüdür) ve tek sayıda 1 bit varsa 1'dir. Çünkü n=2*k+b
, ihtiyacımız olan par(n) = par(k)^b
kötülüğü elde etmek için , yani son bit , önceki bitlerin bit paritesi olacaktı.par(n)==0
b=par(k)
n
Golf Benim ilk çabalar ifade edildi par(k)
, ilk doğrudan en ile bin(k).count('1')%2
birlikte daha sonra, ve biraz manipülasyon .
Eşlik güncellemeleri
Yine de kısa bir ifade yoktu. Bunun yerine, çalışmak için daha fazla bilgi olduğunu fark etmemize yardımcı oldu. Mevcut sayının bit paritesini hesaplamak yerine,
k ----> par(k)
Biz artırmak olarak biz biraz paritesine güncelleyebilir k
için k+1
.
k ----> par(k)
|
v
k+1 ----> par(k+1)
Yani, saydığımız için k=0,1,2,...
, her seferinde sıfırdan hesaplamak yerine sadece mevcut bit paritesini korumamız gerekir. Parite biti güncelleme par(k+1)^par(k)
giden çevrilmiş bit sayısının paritesi ise k
hiç k+1
, yani par((k+1)^k)
.
par(k+1) ^ par(k) = par((k+1)^k)
par(k+1) = par(k) ^ par((k+1)^k)
Formu (k+1)^k
Şimdi hesaplamamız gerekiyor par((k+1)^k)
. Hiçbir yere ulaşmamışız gibi görünebilir, çünkü hesaplama bit paritesi tam olarak çözmeye çalıştığımız problemdir. Ancak, (k+1)^k
forma sahip olarak ifade edilen sayılar 1,3,7,15,..
, yani 2 bit gücünün altında olan, genellikle bit bilgisayar korsanlarında kullanılan bir gerçek . Bunun neden olduğunu görelim.
Arttığımızda k
, ikili taşıyıcıların etkisi sonuncuyu 0
ve hepsini 1
sağa çevirmek, 0
eğer yoksa yeni bir lider oluşturmaktır . Örneğin, almakk=43=0b101011
**
101011 (43)
+ 1
------
= 101100 (44)
101011 (43)
^101100 (44)
------
= 000111 (77)
Taşımaya neden olan sütunlar ile işaretlenmiştir *
. Bunlar var 1
bir değişikliği 0
ve bir taşıma bit geçmek 1
bir vurur kadar kalan ilerleyen tutar, 0
in k
değişir, 1
. Soldan ilerideki herhangi bir bit etkilenmez. Yani, k^(k+1)
bit pozisyonu çekleri değiştirmek k
için k+1
, bu en sağdaki konumlarını bulur 0
ve 1
onun sağa 's. Yani, değişen bitler bir sonek oluşturur, bu nedenle sonuç 0'ın ardından bir veya daha fazla 1'dir. Baştaki sıfırlar olmadan, 1, 11, 111, 1111, ...
2 gücünün altında bir olan ikili sayılar vardır.
Bilgi işlem par((k+1)^k)
Şimdi bunun (k+1)^k
sınırlı olduğunu anladığımızda 1,3,7,15,...
, bu sayıların bit paritesini hesaplamanın bir yolunu bulalım. Burada, faydalı bir gerçek, ve arasında beri 1,2,4,8,16,...
alternatif modülo olmasıdır . Yani, modulo alarak , tam olarak onların bit paritesi olan verir . Mükemmel!3
1
2
2==-1 mod 3
1,3,7,15,31,63...
3
1,0,1,0,1,0...
Yani, güncellemeyi yapabilirsiniz par(k+1) = par(k) ^ par((k+1)^k)
olarak
par(k+1) = par(k) ^ ((k+1)^k)%3
Eşliği b
sakladığımız değişken olarak kullanmak , bu gibi görünüyor
b^=((k+1)^k)%3
Kod yazma
Kodunda birlikte bu koyarak, biz başlatmak k
ve parite bit b
hem 0
sonra defalarca baskı, n=2*k+b
ve güncelleme b=b^((k+1)^k)%3
ve k=k+1
.
46 bayt
k=b=0
exec"print 2*k+b;b^=(k+1^k)%3;k+=1;"*400
Çevrimiçi deneyin!
Biz etrafında parens kaldırıldı k+1
içinde ((k+1)^k)%3
çünkü Python öncelik ilk Neyse, görünüşe garip olarak eklenme yapar.
Kod geliştirmeleri
Doğrudan tek bir değişkenle çalışarak n=2*k+b
ve güncellemeleri doğrudan üzerinde gerçekleştirerek daha iyisini yapabiliriz . Yapmak k+=1
karşılık gelir n+=2
. Ve, güncelleme b^=(k+1^k)%3
karşılık gelir n^=(k+1^k)%3
. İşte, k=n/2
güncellemeden önce n
.
44 bayt
n=0
exec"print n;n^=(n/2+1^n/2)%3;n+=2;"*400
Çevrimiçi deneyin!
Yeniden yazarak kısaltabiliriz n/2+1^n/2
(bunu hatırlayın (n/2+1)^n/2
).
n/2+1 ^ n/2
(n+2)/2 ^ n/2
(n+2 ^ n)/2
Yana /2
geçen biraz kaldırır önce veya xor-ing sonra yaparsanız, hiç önemli değil. Yani biz var n^=(n+2^n)/2%3
. Biz modülo işaret ederek başka byte kaydedebilirsiniz 3
, /2
eşdeğerdir *2
eşdeğerdir -
belirterek, n+2^n
bölünme döşeme olmadan gerçek halving bile böyledir. Bu verirn^=-(n+2^n)%3
41 bayt
n=0
exec"print n;n^=-(n+2^n)%3;n+=2;"*400
Çevrimiçi deneyin!
Son olarak, biz işlemleri birleştirebilirsiniz n^=c;n+=2
içine n=(n+2)^c
nerede, c
biraz. Bu işe yarıyor, çünkü ^c
sadece son bit üzerinde hareket ediyor ve son bit ile +2
ilgilenmiyor, bu yüzden işlemler yolunda gidiyor. Yine, öncelik, parens atlamamıza ve yazmamıza izin verir n=n+2^c
.
39 bayt
n=0
exec"print n;n=n+2^-(n+2^n)%3;"*400
Çevrimiçi deneyin!