Rで解いていないFizzBuzz問題
「Rで解くFizzBuzz問題」を見ていて理解できる事は、Rで高速なコードを書くのはトリッキーだと言う事ですね。素直にCで実装した方が速いかも知れないと言うことで、試してみました。
速度的には、Rで最も速かった「裏 RjpWiki 変態チック版」の約1.5倍という所で、時間にして3割強、短縮できています。Rの速度はインタープリッタの言語としては、かなり驚異的な数字でしょう。Rもループと条件分岐を避ければ、かなり高速になるようです。
試したコードは以下になります。数字の文字列化のオーバーヘッドを多少は押さえていますが、オーソドックスに実装していると思います。なお、仮想マシンを使っていたためかベンチマークの速度は安定しませんでした。
R-FizzBuzz.c
#include <R.h>
#include <Rinternals.h>
char* itoa(int value, char* result, int base);
/*
* FizzBuzz問題を解く
* args: 配列の大きさ
* return: 配列
*/
SEXP FizzBuzz(SEXP n)
{
SEXP ans; /* 戻り値 */
int len, i, m;
char buf[64];
len = INTEGER(n)[0];
PROTECT(ans = allocVector(STRSXP, len));
for(i = 0; i < len; i++) {
m = i + 1;
if(!(m % 3)){
if(!(m % 5)){
SET_STRING_ELT(ans, i, mkChar("FizzBuzz"));
} else {
SET_STRING_ELT(ans, i, mkChar("Buzz"));
}
} else if(!(m % 5)){
SET_STRING_ELT(ans, i, mkChar("Fizz"));
} else {
itoa(m, buf, 10);
SET_STRING_ELT(ans, i, mkChar(buf));
}
}
UNPROTECT(1);
return(ans);
}
char* itoa(int value, char* result, int base) {
if (base < 2 || base > 36) { *result = '\0'; return result; }
char* ptr = result, *ptr1 = result, tmp_char;
const char* num = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz";
int tmp_value;
do {
tmp_value = value;
value /= base;
*ptr++ = num[35 + (tmp_value - value * base)];
} while ( value );
if (tmp_value < 0) *ptr++ = '-';
*ptr-- = '\0';
while(ptr1 < ptr) {
tmp_char = *ptr;
*ptr--= *ptr1;
*ptr1++ = tmp_char;
}
return result;
}