Cバグ?
Telephone Keypad Letter Mapping Fixedを見ていておかしな現象を見つけた。数値を文字コードへ変換する際、7のところだけ "PQRS" と一文字多いので、この部分を吸収するため、
n*25/8-59
とやることでしのいでいた。この "*25/8" の部分を "/.32" に変えると 1B 稼ぐことができるのだが、なぜかうまくいかない。ちょっと調べてみたら、以下のようなことが分かった。
n;main(){ n=56; printf("%d\n",(int)(n/.32)); printf("%d\n",(int)(n/.32)); }
このプログラムをあなごるサーバーに流すと、結果は、
175 174
となる。何ですかねこの違いは。コンパイラのバグ?それとも、CPUのバグ?
調査の続き
あなごるサーバーに bash を使って以下をサブミットしてみた。
echo '#includeint c; main(){ c=56; printf("%d\n",(int)(c/.32)); printf("%d\n",(int)(c/.32)); }'> t.c;gcc -O t.c;./a.out
やはり、出力は、
175 174
となった。ところが、-O を取り除いてやると、
174 174
となった。ということは、gcc のオプティマイザーのバグか?でも、174 というのも気持ち悪い。
c=56; printf("%f\n",c/.32);
だと、
175.000000
だしな。浮動小数点の誤差と丸めモードのためなのか?
さらに調べると
printf()の呼び出しを行うと、その後は、174 になるようだ。printf() が丸めモードを変更して、もとに戻していないのではないかな?
また、以下のように fegetround()を呼んでも 174 になった。
#includeint a,b,n; main(){ n=56; a=fegetround(); printf("%d\n",(int)(n/.32)); printf("%d\n",(int)(n/.32)); b=fegetround(); printf("%d %d\n",a,b); }
#libmをリンクしてやらないと fegetround() が解決できない。
両 printf() は、174 を表示したが、ただ、a, b ともに、0 だった。つまり、丸めモードは「0に向かって丸める」モード。
もしかしたら、main() が呼ばれた段階では丸めモードは不定で、fegetround() は不定だと 0 に設定しているのではないだろうか?また、printf() はフォーマッティングのために、丸めモードを fegetround() でチェックしていて、そのため、0 になってしまうのでは?--- 想像だけどつじつまが合うような気がする。
いずれにせよ、バグではなく言語仕様だとしたら、鬱陶しい仕様だな。