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+bk0,1,...,399b
En yazalım par(x)için biraz parite ait xxor (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)^bkötülüğü elde etmek için , yani son bit , önceki bitlerin bit paritesi olacaktı.par(n)==0b=par(k)n
Golf Benim ilk çabalar ifade edildi par(k), ilk doğrudan en ile bin(k).count('1')%2birlikte 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 kiç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 khiç 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)^kforma 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 0ve hepsini 1sağa çevirmek, 0eğ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 1bir değişikliği 0ve bir taşıma bit geçmek 1bir vurur kadar kalan ilerleyen tutar, 0in kdeğişir, 1. Soldan ilerideki herhangi bir bit etkilenmez. Yani, k^(k+1)bit pozisyonu çekleri değiştirmek kiçin k+1, bu en sağdaki konumlarını bulur 0ve 1onun 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)^ksı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!3122==-1 mod 31,3,7,15,31,63...31,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 bsakladığı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 kve parite bit bhem 0sonra defalarca baskı, n=2*k+bve güncelleme b=b^((k+1)^k)%3ve 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+1iç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+bve güncellemeleri doğrudan üzerinde gerçekleştirerek daha iyisini yapabiliriz . Yapmak k+=1karşılık gelir n+=2. Ve, güncelleme b^=(k+1^k)%3karşılık gelir n^=(k+1^k)%3. İşte, k=n/2gü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 /2geç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, /2eşdeğerdir *2eşdeğerdir -belirterek, n+2^nbö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+=2içine n=(n+2)^cnerede, cbiraz. Bu işe yarıyor, çünkü ^csadece son bit üzerinde hareket ediyor ve son bit ile +2ilgilenmiyor, 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!