C, 59 bayt
i;f(char*s){while(*s&3?*s&9||(i+=i+*s%5):putchar(i),*s++);}
Sihirli sayılar, her yerde sihirli sayılar!
(Ayrıca, C, Python, JS, PHP ve Ruby'den daha kısa? Duyulmamış!)
Bu, dizgeyi girdi olarak alan ve STDOUT işlevine çıkan bir işlevdir.
Bakış
Temel yapı:
i; // initialize an integer i to 0
f(char*s){
while(...); // run the stuff inside until it becomes 0
}
Burada, "içerdeki eşyalar", ardından ,*s++
virgül işleyicisinin yalnızca ikinci argümanının değerini döndürdüğü bir demet koddur . Bu nedenle, bu dizge boyunca çalışacak ve çıkmadan önce *s
son NUL baytı dahil (her postfix ++
önceki değeri döndürdüğü için) her karaktere ayarlanacaktır .
Diğerlerine bir bakalım:
*s&3?*s&9||(i+=i+*s%5):putchar(i)
Üçlü ve kısa devre devre dışı bırakarak ||
, bu genişletilebilir
if (*s & 3) {
if (!(*s & 9)) {
i += i + *s % 5;
}
} else {
putchar(i);
}
Bu sihirli sayılar nereden geliyor? İşte dahil olan tüm karakterlerin ikili gösterimleri:
F 70 01000110
B 66 01000010
i 105 01101001
z 122 01111010
u 117 01110101
32 00100000
\0 0 00000000
Öncelikle, boşluğu ve NUL'yi karakterlerin geri kalanından ayırmamız gerekiyor. Bu algoritmanın çalışma şekli, "geçerli" sayının bir akümülatörünü tutar ve dizginin bir boşluğuna veya sonuna ulaştığında yazdırır '\0'
. Bunu fark ederek ' '
ve '\0'
ayarlanan en az iki önemli bitin hiçbirine sahip olmayan tek karakterlerdir 0b11
, karakter boşluk veya NUL ise ve sıfır değilse sıfır karakterini sıfıra getirebiliriz .
Daha derine inerek, ilk "if" dalında, şimdi onlardan biri olan bir karaktere sahibiz FBizu
. Sadece akümülatörü F
s ve B
s'de güncellemeyi seçtim , bu yüzden s'yi filtrelemek için bir yola ihtiyacım vardı izu
. Uygun şekilde F
ve B
her ikisi de yalnızca ikinci, üçüncü veya yedinci en az önemli bit ayarlarına sahiptir ve diğer tüm sayılar en az bir başka bit setine sahiptir. Aslında, hepsinde ilk veya dördüncü en az anlamlı bit bulunur. Bu yüzden, bitsel AND ile 0b00001001
, 9 olan, 0 için elde olan F
ve B
ve sıfır olmayan, aksi takdirde.
Biz bir olduğunu belirledikten sonra F
ya B
, onları eşleme yapabilirsiniz 0
ve 1
çünkü onların modülüne 5 alarak sırasıyla F
olduğunu 70
ve B
bir 66
. Sonra pasajı
i += i + *s % 5;
sadece demenin bir golf yolu
i = (i * 2) + (*s % 5);
olarak da ifade edilebilir
i = (i << 1) | (*s % 5);
bu yeni biti en az önemli pozisyona yerleştirir ve her şeyi 1'in üzerine kaydırır.
"Fakat bekle!" protesto edebilirsin. “Yazdırdıktan sonra ne i
zaman tekrar 0'a sıfırlanır?” Eh, putchar
onun argümanını unsigned char
8 bit büyüklüğünde olan bir argümanına atar . Bu, 8. en az anlamlı bitin (yani önceki yinelemelerin önemsiz) geçmişindeki her şeyin atıldığı ve bunun için endişelenmemize gerek olmadığı anlamına gelir.
Sayesinde @ETHproductions yerine öneren 57
ile 9
, bir byte tasarruf!