m2

FizzBuzz 再燃

今更だけど FizzBuzz に制限をつけると面白かった。

元ネタ

【問題】

1から100までの数を表示するプログラムを書け。
ただし3の倍数のときは数の代わりに「Fizz」と表示。
5の倍数のときは「Buzz」と表示。
3と5両方の倍数の場合には「FizzBuzz」と表示すること。

解答言語は PHP とする。
また、以下のテンプレートを使用すること。

for($i=1;$i<=100;$i++){
echo ### FreeCode ###;
}

### FreeCode ### 部分を三項演算子を用い、()を用いずにコーディングして解を示せ。

                  • -

つまり PHP三項演算子を使って、()で優先順位付せずに解いてネ、ってこと。

http://d.hatena.ne.jp/levin_gsp/20080904/1220533204

表示部分を()を使わずにワンライナーで書くというのがキモ。
私は PHP を避けているので JavaScript で。ついでに三項演算子も無くしました。

(function(){
  var s = [];
  for(var i=1;i<=100;i++){
    s[i-1]=['',i][i%3*i%5*-1>>>31]+['Fizz',''][i%3*-1>>>31]+['Buzz',''][i%5*-1>>>31];
  }
  alert(s);
})()

紛らわしいのは「i%3*i%5」と「x*-1>>>31」の2点。

「i%3*i%5」は、「3 か 5 のどちらかで割り切れたら 0」という意味で、正確には「(i % 3) * (i % 5)」としたいところ。この式だと「%」も「*」も演算の優先順位は同じなので左から「*1

    正の整数( 3): 00000000 00000000 00000000 00000011
        3 >>>  1: 00000000 00000000 00000000 00000001
        3 >>> 31: 00000000 00000000 00000000 00000000 (0)
    負の整数(-3): 11111111 11111111 11111111 11111101
       -3 >>>  1: 01111111 11111111 11111111 11111110
       -3 >>> 31: 00000000 00000000 00000000 00000001 (1)

x は「割り切れたら 0、そうでなければ正の整数」が入っています。この演算によって正の整数が「1」に変換され、つまりは「割り切れたら 0、そうでなければ 1」という意味になります。

*1:i % 3) * i) % 5)」と評価されちゃいます。 でもこれでも問題無し。例えば i が 5 で割り切れるとしたとき、「i = 5 * x」と表現できて、その時の i を 3 で割った余りを d とすると「d * 5 * x」=「5 * (x * d)」となり、結局 5 で割り切れます。 「x*-1>>>31」はビット演算。 JavaScript ではビット演算を行う場合に左辺を32ビットの整数にします。左辺が正の整数の場合は32ビット目が「0」、負の場合は「1」になっていますから、31ビット0埋め右シフトをすると、正の整数なら 0、負の整数なら 1 と評価されます((この Java プログラムで確認できます。http://gist.github.com/16208