39 Bytes bekommen
Dies ist eine Erklärung, wie ich zu einer 39-Byte-Lösung gekommen bin, die Dennis und JonathanFrech ebenfalls separat gefunden haben. Oder vielmehr, es erklärt, wie man im Nachhinein zu der Antwort gelangen kann, und zwar auf eine Weise, die viel schöner ist als mein tatsächlicher Weg dahin, der voller schlammiger Überlegungen und Sackgassen war.
n=0
exec"print n;n=n+2^-(n+2^n)%3;"*400
Wenn Sie dies etwas weniger golfen und mit mehr Parens schreiben, sieht das so aus:
n=0
for _ in range(400):
print n
n=(n+2)^(-((n+2)^n))%3
Bitparitäten
Wir beginnen mit einer Idee von meiner 47-Byte - Lösung alle Zahlen der Form ausgeben , n=2*k+bwo kaufwärts zählt, 0,1,...,399und bist ein Paritätsbit, das die Gesamtzahl von 1 macht , auch.
Schreiben wir par(x)für die Bitparität von x, das ist das xor ( ^) aller Bits in x. Dies ist 0, wenn es eine gerade Anzahl von 1-Bits gibt (die Anzahl ist böse), und 1, wenn es eine ungerade Anzahl von 1-Bits gibt. Denn n=2*k+bwir haben par(n) = par(k)^b, um das Böse zu erreichen par(n)==0, müssen wir b=par(k)das letzte Bit nder Bit-Parität der vorhergehenden Bits sein.
Meine ersten Bemühungen um Golf waren die auf ausdrücken par(k), zunächst direkt mit bin(k).count('1')%2, und dann mit Bit - Manipulation .
Paritätsaktualisierungen
Trotzdem schien es keinen kurzen Ausdruck zu geben. Stattdessen hat es geholfen zu erkennen, dass es mehr Informationen gibt, mit denen man arbeiten kann. Anstatt nur die Bit-Parität der aktuellen Zahl zu berechnen,
k ----> par(k)
wir können die Bit - Parität aktualisieren , wie wir erhöhen kzu k+1.
k ----> par(k)
|
v
k+1 ----> par(k+1)
Das heißt, da wir aufwärts zählen k=0,1,2,..., müssen wir nur die aktuelle Bitparität beibehalten, anstatt sie jedes Mal von Grund auf neu zu berechnen. Die Bitparitätsaktualisierung par(k+1)^par(k)ist die Parität der Anzahl von Bits, die beim Wechseln von knach k+1, d par((k+1)^k). H., Gewechselt werden .
par(k+1) ^ par(k) = par((k+1)^k)
par(k+1) = par(k) ^ par((k+1)^k)
Eine Form von (k+1)^k
Jetzt müssen wir rechnen par((k+1)^k). Es scheint, als hätten wir nichts erreicht, weil die Berechnung der Bit-Parität genau das Problem ist, das wir zu lösen versuchen. Zahlen, die als ausgedrückt werden, (k+1)^khaben jedoch die Form 1,3,7,15,.., dh eine unter einer Potenz von 2, eine Tatsache, die häufig in Bit-Hacks verwendet wird . Mal sehen, warum das so ist.
Wenn wir inkrementieren k, besteht der Effekt der binären Überträge darin, die letzten 0und alle 1nach rechts zu invertieren und eine neue Führung zu erzeugen, 0wenn keine vorhanden wäre. Nehmen wir zum Beispielk=43=0b101011
**
101011 (43)
+ 1
------
= 101100 (44)
101011 (43)
^101100 (44)
------
= 000111 (77)
Die Spalten, die einen Übertrag verursachen, sind mit gekennzeichnet *. Diese haben eine 1Änderung von a 0und leiten ein Übertragsbit von weiter 1, das sich so lange nach links ausbreitet, bis es ein 0In trifft k, das sich zu ändert 1. Etwaige Bits weiter links bleiben davon unberührt. Also, wenn k^(k+1)überprüft , welche Positionen ändern biß kzu k+1, findet er die Positionen der äußersten rechten 0und der 1‚s auf der rechten Seite . Das heißt, die geänderten Bits bilden ein Suffix. Das Ergebnis sind also Nullen, gefolgt von einer oder mehreren Einsen. Ohne die führenden Nullen gibt es Binärzahlen 1, 11, 111, 1111, ..., die unter einer Zweierpotenz liegen.
Computing par((k+1)^k)
Nun, da wir verstehen, dass dies auf (k+1)^kbeschränkt ist 1,3,7,15,..., wollen wir einen Weg finden, die Bitparität solcher Zahlen zu berechnen. Hier ist eine nützliche Tatsache, dass 1,2,4,8,16,...abwechselnd modulo 3zwischen 1und 2, da 2==-1 mod 3. Also, unter 1,3,7,15,31,63...Modulo 3gibt 1,0,1,0,1,0..., was genau ihre Bit-Paritäten sind. Perfekt!
So können wir das Update durchführen par(k+1) = par(k) ^ par((k+1)^k)als
par(k+1) = par(k) ^ ((k+1)^k)%3
Unter Verwendung bals Variable wir die Parität in sind speichern, das sieht aus wie
b^=((k+1)^k)%3
Code schreiben
Setzen wir dies in Code zusammen, starten wir kund setzen das Paritätsbit bbeide auf 0, drucken n=2*k+bund aktualisieren dann wiederholt b=b^((k+1)^k)%3und k=k+1.
46 Bytes
k=b=0
exec"print 2*k+b;b^=(k+1^k)%3;k+=1;"*400
Probieren Sie es online!
Wir haben Parens k+1in entfernt, ((k+1)^k)%3weil Python die Addition sowieso zuerst ausführt, komisch, wie es aussieht.
Code Verbesserungen
Wir können es jedoch besser machen, indem wir direkt mit einer einzelnen Variablen arbeiten n=2*k+bund die Aktualisierungen direkt darauf durchführen. Tun k+=1entspricht n+=2. Und die Aktualisierung b^=(k+1^k)%3entspricht n^=(k+1^k)%3. Hier k=n/2vor dem Update n.
44 Bytes
n=0
exec"print n;n^=(n/2+1^n/2)%3;n+=2;"*400
Probieren Sie es online!
Wir können n/2+1^n/2dies (n/2+1)^n/2durch Umschreiben verkürzen (denken Sie daran )
n/2+1 ^ n/2
(n+2)/2 ^ n/2
(n+2 ^ n)/2
Da /2das letzte Bit entfernt wird, spielt es keine Rolle, ob wir es vor oder nach dem xor-ing machen. Also haben wir n^=(n+2^n)/2%3. Wir können ein weiteres Byte speichern mit der Feststellung , dass Modulo 3, /2gleichwertig ist *2äquivalent ist -, unter Hinweis darauf , dass n+2^nist sogar so die Division ohne Boden tatsächliches Halbieren ist. Das gibtn^=-(n+2^n)%3
41 Bytes
n=0
exec"print n;n^=-(n+2^n)%3;n+=2;"*400
Probieren Sie es online!
Schließlich können wir die Operationen n^=c;n+=2in kombinieren n=(n+2)^c, wo cein bisschen ist. Dies funktioniert, weil ^cnur das letzte Bit bearbeitet wird und das letzte Bit +2nicht berücksichtigt wird, sodass die Operationen pendeln. Wieder lässt uns der Vorrang die Parens auslassen und schreiben n=n+2^c.
39 Bytes
n=0
exec"print n;n=n+2^-(n+2^n)%3;"*400
Probieren Sie es online!