2013/04/22

【副部長の】はじめてのpolyglot【不定期連載】

言語はCとrubyとpython


#define p
#define M 0;k,j,b[600];main(i){for(;i++<24;)for(k=1;i*k++<600;)b[i*k]=1;for(;j++<542;)b[j]||printf("%d\n",j);}m
i=M=0;
#if 0
print"2\n3\n5\n7\n11\n13\n17\n19\n23"
'''a'
=begin
'a'''
p=7;
s='111@A\"1A1!a1A21@P1S02#2112a!aP2AA22PPA213AA34'
m='Y$s\x15\x15C*iV\'Tp\x0d'
P=[1if int(z)==1 else-1for z in list(''.join([y if len(y)==7 else'0'*(7-len(y))+y for y in[bin(ord(x))[2:]for x in list(m)]]))]
for c in [ord(x) for x in list(s)]:
 print p*4+P[i]
 p+=(c>>4)-2
 i+=1
 print p*4+P[i]
 p+=c&15
 i+=1
print p*4+P[i]
'''a'
=end
print"\n"
2.step(542,1){|a|$M=0;2.step(23,1){|b|if a%b==0then$M=1;break;end};if$M==0then p a end};
'a'''
#endif

解説は後で書く.

まず,C言語の説明からしたいと思います.
このソースをプリプロセスにかけると以下のようになります.

i=0;k,j,b[600];main(i){for(;i++<24;)for(k=1;i*k++<600;)b[i*k]=1;for(;j++<542;)b[j]||printf("%d\n",j);}m=0;

次に,整形して見やすくします.

k,j,b[600];
main(i) {
    for(;i++<24;) {
        for(k=1;i*k++<600;) {
            b[i*k]=1;
        }
    }
    for(;j++<542;) {
        b[j]||printf("%d\n",j);
    }
}

i=0;m=0は必要無いので削除してしまいました.
この時点のコードで,解説に入っていきたいと思います.
まず,変数宣言ですが,グローバル変数は型名を宣言しないとintになり,さらに0に初期化されることを利用して,型宣言,初期化の代入を省いています.
main(i)のiですが,main関数の引数にはint argcが入ることを利用し,また型宣言がないと型がintになることを利用して,int iを宣言しています.
初期化は,argcは引数を指定せずにプログラムを実行すると1が入ることを利用して,実行すると1が入る仕組みになっています.

アルゴリズムは単純なエラトステネスの篩です.

最初の二つのfor文でふるい分けをしています.
外側のfor文で2から24までの数をiに代入し,内側のfor文でi*2以降の全ての倍数にフラグを立てています.
高速化の面ではきちんと素数の倍数でフラグを立てるべきですが,倍数の倍数でも別に結果には変わりないので省いています.
外側のfor文の条件でi++<24となっているのは,プログラムを実行したときiに1が入ってしまうので,i<24を比較した後に後置インクリメントでi+=1をしています.
 このようにすることで,i<24を比較した後,内側のfor文に入る前にiが2になってくれます.
内側のfor文でiの倍数にフラグを立てています.
このfor文も比較の時はkの値をそのまま使って,中の文に入る前にk+=1をしています.
このようにしないと,iが素数の場合,for文のb[i*k]=1;がb[i*1]=1;となってしまい,iは素数であるにも関わらず,b[i]が1になってしまいます.

 次のfor文で素数の出力をしています.
for文の中身はb[600]を順番に542まで調べて,b[j]==0の時のみprintfしています.
C言語の論理積と論理和,つまり&&と||はそれぞれ次のような特徴があります.

論理積は (expr_1&&expr_2&&…&&expr_N) と書くとき,expr_nが偽ならそれ以降,つまりexpr_n+1以降は評価しません.

また,論理和は (expr_1||expr_2||…||expr_N) と書くとき,expr_nが真ならそれ以降,つまりexpr_n+1以降は評価しません.

このことを利用し,
if(expr_1==0) {
    expr_2;
}

expr_1||expr_2;
と書くことができます.
これを利用してフラグが立っていない添字のみを出力しています.

0 件のコメント:

コメントを投稿