C言語 | Fizzbuzz 問題でビット演算を用いる
<問>
以下の Fizz-buzz 問題の C/C++ プログラムを書け。
- 数値ゼロから 200 までインクリメント出力する。ただし 下記2. の条件を満たす場合はこれを出力する。
- 素数 3, 5, 7 についてそれぞれの倍数である場合は 「(素数) n」と出力する。ただしこれら素数の最小公倍数である場合はそちらを優先し「(最小公倍数) n」と出力する。(e.g.参照)
e.g. 210 なら 105n, 70 なら 35n, 63 なら 21n, 14 なら 7n, 30 なら 15n, 10 なら 5n, 6 なら 3n
解:ビット演算を使う方法
<ソース(全)>
#include <iostream>
using namespace std;
int main(void){
char *name[] = { "(reserved)" , "3n" , "5n", "15n", "7n", "21n", "35n", "105n"};
int idx;
for (int n = 0; n <= 200; n++) {
idx= 7*(n !=0) & 4*(n%7 == 0) + 2*(n%5 == 0)+(n%3 == 0); //入力数字の条件分岐に相当する処理
idx==0 ? cout<< n : cout << name[idx]; cout << endl;
}
}
ビット演算を用いると Fizz-Buzz の条件分岐は ほとんど 1行で済む。条件ごとに 2^n のマスクを取ること。
別解1:三項演算子とポインタ
<ソース(全)>
#include <stdio.h>
int main(){
char *str="0 \n\0 105n \n\0 035n \n\0 021n \n\0 015n \n\0 007n \n\0 005n \n\0 003n \n\0 %d \n\0";
for(int i=-1;++i<200;){
printf(str+(i!=0?i%105?i%35?i%21?i%15?i%7?i%5?i%3?64:56:48:40:32:24:16:8:0),i);
}
}
三項演算子を使った条件先がポインタ演算となっている。
別解2:多次元配列を用いる
<ソース(全)>
#include <iostream>
using namespace std;
int main(void){
char idx;
for (int n = 0; n <= 200; n++) {
idx= (char[2][2][2]){'A', 'B', 'C', 'D','E', 'F', 'G', 'H'}[n%7 == 0][n%5 == 0][n%3 == 0];
(idx =='N' || n ==0) ? cout<< n : cout << idx; cout << endl;
}
}
ビット演算の場合と違ってビットマスクを取る必要がないので比較的わかりやすい。