カメヲラボ

主にプログラミングとお勉強全般について書いてます

ISBN(4)

超絶テクニック(その3)

最後は超絶テクニック1と2を融合させる。
前回のテクニック2で書いたコードをもう一度見てみると、


001 main(n){
002 int a=11,b,s;
003 for(;a--;){
004 n=getchar();
005 if(n==63)b=a;
006 else if(n==88)s+=10;
007 else if(n>=48&&n<=57)s+=(n-48)*a;
008 }
009 s-=b;
010 for(;s%11;a++)s+=b;
011 printf(a+b?"%d":"X",a);
012 }
9行目の式。sにbを足したり引いたりすることで、失敗(あるいは最後の一桁がX)の判定値をコントロールできるのだ。何も足さなければ、つまりこの式を書かなければ、1〜9の値が見つからなければ10行目のループはa=10で終了する。コードをスッキリさせるには10でなく-1で終わらせたいので、事前にsから一回だけbを引いておけばよいのだ。


この方法を使えば、文字コードを直接使う場合に起こる問題を解決することが出来る。


1〜10の整数値に変換して計算する場合と、文字コードのままで計算する場合の問題点は、11での剰余に差があるということ。具体的に書くと、


0%11=0
'0'%11=48%11=4
というように、変換された整数値と文字コードでは、11の剰余に4の差が出てしまうので、ここで先ほどのテクニックを利用する。

s-=b → s=s-b
と一旦しておいて、ここにbを4回加える

s = s-b+b*4 = s+3*b
つまり、

s+=3*b
とすればよいことになる。こうして2つのテクニックを融合することで、110byteの壁をすんなり打ち破ることができるのだ。


以下に上記のサンプルとしてコード(106byte)を掲載しておく。


a=11,b,s;
main(n){
for(;a--;b=n?b:a)n=getchar()%63,s+=n*a;
s+=b*3;
for(;s%11;++a)s+=b;
printf(a+b?"%d":"X",a);
}