Obtenir 39 octets
C'est une explication de la façon dont j'ai obtenu une solution de 39 octets, que Dennis et Jonathan Frech ont également trouvée séparément. Ou plutôt, il explique comment on pourrait arriver à la réponse avec le recul, d’une manière beaucoup plus agréable que mon chemin actuel, qui était plein de raisonnements boueux et d’impasses.
n=0
exec"print n;n=n+2^-(n+2^n)%3;"*400
En écrivant ceci un peu moins golfé et avec plus de parens, cela ressemble à:
n=0
for _ in range(400):
print n
n=(n+2)^(-((n+2)^n))%3
Bits parités
Nous commençons par une idée de ma solution de 47 octets qui consiste à sortir tous les nombres de la forme n=2*k+boù ils kcomptent 0,1,...,399et bconstituent un bit de parité qui rend le nombre total de 1 égal.
Écrivons par(x)pour la parité de bitsx , c’est-à-dire que xor ( ^) contient tous les bits x. C'est 0 s'il y a un nombre pair de 1 bits (le nombre est mauvais) et 1 s'il y a un nombre impair de 1 bits. Pour n=2*k+b, nous avons par(n) = par(k)^b, pour ainsi atteindre le mal dont par(n)==0nous avons besoin b=par(k), à savoir le dernier bit de nsoit la parité binaire des bits précédents.
Mes premiers efforts au golf ont été d’exprimer le par(k), d’abord directement avec bin(k).count('1')%2, puis avec un peu de manipulation .
Mises à jour de parité
Pourtant, il ne semblait pas y avoir d’expression courte. Au lieu de cela, cela a aidé à réaliser qu'il y avait plus d'informations avec lesquelles travailler. Plutôt que de simplement calculer la parité de bits du nombre actuel,
k ----> par(k)
nous pouvons mettre à jour la parité bit comme on incrémente kà k+1.
k ----> par(k)
|
v
k+1 ----> par(k+1)
En d'autres termes, puisque nous k=0,1,2,...comptons, nous devons simplement maintenir la parité de bits actuelle au lieu de la calculer à partir de zéro à chaque fois. La mise à jour de parité de bit par(k+1)^par(k)est la parité du nombre de bits basculés en allant kvers k+1, soit par((k+1)^k).
par(k+1) ^ par(k) = par((k+1)^k)
par(k+1) = par(k) ^ par((k+1)^k)
Forme de (k+1)^k
Maintenant, nous devons calculer par((k+1)^k). Il peut sembler que nous n'ayons nulle part abouti, car le calcul de la parité entre bits est exactement le problème que nous essayons de résoudre. Mais, les nombres exprimés sous (k+1)^kla forme 1,3,7,15,.., c’est-à-dire une valeur inférieure à une puissance de 2, fait souvent utilisé pour le piratage des bits . Voyons pourquoi.
Lorsque nous incrémentons k, l’effet des transferts binaires est d’inverser le dernier 0et tout 1à sa droite, créant ainsi un nouveau principal 0s’il n’y en avait pas. Par exemple, prenezk=43=0b101011
**
101011 (43)
+ 1
------
= 101100 (44)
101011 (43)
^101100 (44)
------
= 000111 (77)
Les colonnes provoquant un report sont identifiées par *. Celles-ci ont un 1changement en a 0et transmettent un peu de retenue 1, ce qui continue à se propager jusqu'à ce qu'il frappe un 0dans k, qui devient 1. Les bits plus à gauche ne sont pas affectés. Ainsi, lorsque les k^(k+1)contrôles qui changent les positions de bits kà k+1, il trouve les positions des plus à droite 0et 1est à sa droite. C'est-à-dire que les bits modifiés forment un suffixe, le résultat est donc un 0 suivi d'un ou plusieurs 1. Sans les zéros au début, il existe des nombres binaires 1, 11, 111, 1111, ...inférieurs à une puissance de 2.
L'informatique par((k+1)^k)
Maintenant que nous comprenons que cela (k+1)^kse limite à 1,3,7,15,..., trouvons un moyen de calculer la parité de bits de ces nombres. Ici, un fait utile est ce 1,2,4,8,16,...modulo alternatif 3entre 1et 2, depuis 2==-1 mod 3. Donc, en prenant 1,3,7,15,31,63...modulo 3donne 1,0,1,0,1,0..., qui sont exactement leurs parités de bits. Parfait!
Donc, nous pouvons faire la mise par(k+1) = par(k) ^ par((k+1)^k)à jour en tant que
par(k+1) = par(k) ^ ((k+1)^k)%3
En utilisant bcomme variable dans laquelle nous stockons la parité, cela ressemble à
b^=((k+1)^k)%3
Écrire le code
En regroupant cela dans le code, nous commençons ket le bit de parité bà 0, puis, imprimons n=2*k+bet mettons à jour de manière répétée b=b^((k+1)^k)%3et k=k+1.
46 octets
k=b=0
exec"print 2*k+b;b^=(k+1^k)%3;k+=1;"*400
Essayez-le en ligne!
Nous avons retiré parens autour k+1de ((k+1)^k)%3parce que la priorité Python fait d'abord l'addition de toute façon, bizarre qu'il regarde.
Améliorations du code
Nous pouvons toutefois faire mieux en travaillant directement avec une seule variable n=2*k+bet en effectuant les mises à jour directement sur celle-ci. Faire k+=1correspond à n+=2. Et, mise b^=(k+1^k)%3à jour correspond à n^=(k+1^k)%3. Ici, k=n/2avant de mettre à jour n.
44 octets
n=0
exec"print n;n^=(n/2+1^n/2)%3;n+=2;"*400
Essayez-le en ligne!
Nous pouvons raccourcir n/2+1^n/2(rappelez-vous (n/2+1)^n/2) en réécrivant
n/2+1 ^ n/2
(n+2)/2 ^ n/2
(n+2 ^ n)/2
Puisque /2supprime le dernier bit, peu importe si nous le faisons avant ou après le xor-ing. Donc nous avons n^=(n+2^n)/2%3. Nous pouvons économiser un autre octet en notant que modulo 3, /2est équivalent *2à -, en notant que n+2^nmême si la division est divisée en deux sans plancher. Cela donnen^=-(n+2^n)%3
41 octets
n=0
exec"print n;n^=-(n+2^n)%3;n+=2;"*400
Essayez-le en ligne!
Enfin, nous pouvons combiner les opérations n^=c;n+=2en n=(n+2)^c, où cest un peu. Cela fonctionne car ^cagit uniquement sur le dernier bit et +2ne se soucie pas du dernier bit; les opérations sont donc commutées. Encore une fois, la préséance nous permet d'omettre les parens et d'écrire n=n+2^c.
39 octets
n=0
exec"print n;n=n+2^-(n+2^n)%3;"*400
Essayez-le en ligne!