C、59バイト
i;f(char*s){while(*s&3?*s&9||(i+=i+*s%5):putchar(i),*s++);}
マジックナンバー、どこでもマジックナンバー!
(また、CはPython、JS、PHP、Rubyよりも短いですか?
これは、入力として文字列を受け取り、STDOUTに出力する関数です。
ウォークスルー
基本構造は次のとおりです。
i; // initialize an integer i to 0
f(char*s){
while(...); // run the stuff inside until it becomes 0
}
ここでは、「内部の内容」はに続くコードの束で,*s++
あり、カンマ演算子は2番目の引数の値のみを返します。したがって、終了する前に、これは文字列*s
全体を実行し、末尾のNULバイトを含むすべての文字に設定されます(postfix ++
は前の値を返すため)。
残りを見てみましょう:
*s&3?*s&9||(i+=i+*s%5):putchar(i)
三元および短絡をはがすと||
、これは
if (*s & 3) {
if (!(*s & 9)) {
i += i + *s % 5;
}
} else {
putchar(i);
}
これらのマジックナンバーはどこから来たのですか?関連するすべての文字のバイナリ表現は次のとおりです。
F 70 01000110
B 66 01000010
i 105 01101001
z 122 01111010
u 117 01110101
32 00100000
\0 0 00000000
最初に、スペースとNULを残りの文字から分離する必要があります。このアルゴリズムの動作方法は、「現在の」数のアキュムレータを保持し、スペースまたは文字列の終わり(つまり'\0'
)に達するたびにそれを出力します。ことを注目して' '
と'\0'
設定された2つの最下位ビットのいずれかを持っていない唯一の文字であるが、我々は、ビット単位のANDできると文字0b11
の文字がそれ以外のスペースやNULとゼロでない場合には、ゼロを取得します。
深く掘り下げると、最初の「if」ブランチで、次のいずれかのキャラクターができましたFBizu
。F
sとB
sのアキュムレータのみを更新することを選択したため、sを除外する方法が必要でしたizu
。便利なことにF
、B
両方とも2番目、3番目、または7番目の最下位ビットのみが設定されており、他のすべての数値には少なくとも1つの他のビットが設定されています。実際、それらはすべて最初または4番目の最下位ビットを持っています。したがって、ビットごとにANDを使用してANDを実行できます0b00001001
。これは、9でありF
、B
andが0で、それ以外の場合はゼロではありません。
F
or があることを確認したら、is およびis であるため、それらのモジュラス5を取得することによりB
、0
およびにマッピングできます。次にスニペット1
F
70
B
66
i += i + *s % 5;
ただのゴルフのような言い方です
i = (i * 2) + (*s % 5);
次のように表現することもできます
i = (i << 1) | (*s % 5);
最下位の位置に新しいビットを挿入し、他のすべてを1にシフトします。
"ちょっと待って!" あなたは抗議するかもしれません。「印刷後i
、いつ0にリセットされますか?」さて、putchar
引数をにキャストするとunsigned char
、たまたま8ビットのサイズになります。つまり、8番目の最下位ビット(つまり、以前の反復からのジャンク)を超えるものはすべて破棄され、心配する必要はありません。
おかげ@ETHproductions交換することを示唆しているため57
に9
、バイトを節約!