プログラミングを上達させたい

情報学専攻の大学院→放送局でCMの営業など@大阪→舞台俳優&IT営業@東京

Pascalと大きな数についてと、最近のコンテストの話

はい。
最近、色々とコンテストがありますね。
すごく楽しいです。


天下一プログラマーコンテストはレベルが高くて、全く歯が立ちませんでした。
明日が予選Bですが、何かしら意味のある順位になれる気はしません。皆さん、すごいです。

また、code formulaにも登録しました。
20日に行われた、予選Aに出ました。
こちらも、2問目に凡ミスで時間がかかってしまい、3問目は解けず、結果として本戦出場はまずないような順位になりました。
やはり、本戦(しかも交通費が出る!)を狙って、かなりの人数が参加していました。むむぅ

嬉しいこととして、参加してみた、CEDEC AI Challenge 2014は本戦を通過することが出来ました。
16人までが決勝に進めるという決まりで、60人前後の中12位でした。ラッキーです。
こちらの本戦には参加することにしたので、これから楽しみです。
プログラムを改良しないと。ただ、対戦用サーバーがもう動いてないので、改良してもそれが良いことかどうか調べられないかも。どうしよ。


以上が最近の近況で、ここからがPascalの話。
まだ懲りずにPascalで問題を解いています。
上記のcode formulaも、Pascalで解きました。Pascalでの提出は僕1人のみ。
これだけが誇りです。

Pascalは大きい整数が扱いにくいです。
これを考えるきっかけとなったのは、この問題
Pascalで実際の問題を解いてみようとしてやっていた、5問目?くらいだったように思います。

この問題で満点(101点)を何も考えずに獲得するには、だいたい10の11乗がちゃんと表せたらうれしいです。
ただ、Pascalにはそれが結構キツいのですな。
というわけで、基本的な型がどれくらいなのか、見てみましょう。
よく参考にしているこちらのサイトでは、どうやら普通のCで使えるものより1段階分足りないような感じ。
実際にideoneで動作確認をしてみました。
int、longintを試してみます。試すコードはこんな感じ。まずIntから。

program test(input, output);

var
	a : Integer;
begin

	a := 1;
	while true do
		begin
			writeln(a);
			a := a * 10
		end	

	
end.
Runtime error	time: 0 memory: 276 signal:25
1
10
100
1000
10000
-31072
16960
-27008
-7936
(以下略)

本当に、これだけなのですね。
5桁までって。

次にLongintです。

program test(input, output);

var
	a : Longint;
begin

	a := 1;
	while true do
		begin
			writeln(a);
			a := a * 10
		end	

	
end.
Runtime error	time: 0 memory: 276 signal:25
1
10
100
1000
10000
100000
1000000
10000000
100000000
1000000000
1410065408
1215752192
-727379968
(以下略)

これで10の9乗までです。
Integerよりは圧倒的に大きいですが、これでもなぁ・・・

調べてみると、大きい数を表すのにCardinal型、そしてExtended型というのがあるとのこと。

Cardinal型について色々やってみました。これは非負整数を表すものとのこと。
とりあえず、どこまで大きいのがいけるか。上と同じやり方で確かめます。

program test(input, output);

var
	a : Cardinal;
begin

	a := 1;
	while true do
		begin
			writeln(a);
			a := a * 10
		end	

	
end.
Runtime error	time: 0 memory: 276 signal:25
1
10
100
1000
10000
100000
1000000
10000000
100000000
1000000000
1410065408
1215752192
3567587328
(以下略)

この試し方だと、挙動はLongintと同じ感じですね。

次に、本当に負の数がダメなのかの確かめ。一応自分でやっときたかったので。

program test(input, output);

var
	a : Cardinal;
begin

	a := 3;
	while true do
		begin
			writeln(a);
			a := a - 1
		end	

	
end.
Runtime error	time: 0 memory: 232 signal:25
3
2
1
0
4294967295
4294967294
4294967293
4294967292
4294967291
(以下略)

本当に無理でした。
これだと、Longintの下位互換って感じですね。
その分なにか嬉しいことがあるのでしょうか。

最後にExtended型の方を。

program test(input, output);

var
	a : Extended;
begin

	a := 1;
	while true do
		begin
			writeln(a);
			a := a * 10
		end	

	
end.
Runtime error	time: 0.07 memory: 276 signal:25
 1.0000000000000000E+0000
 1.0000000000000000E+0001
 1.0000000000000000E+0002
 1.0000000000000000E+0003
.....(中略)
 1.0000000000000000E+0028
 1.0000000000000000E+0029
 1.0000000000000000E+0030
(以下略)

お!これは大きい数が扱えるぞ!!!

なんて思っていたのですが、AtCoderに提出してみると、Extended型はCE(コンパイルエラー)になりました。
Cardinal型は大丈夫でしたが、Longintと同じだしなぁ・・・

結局、解決策は見つかりませんでした。
自分で、あの長桁計算を実装するしかないのでしょうか。えぇぇ・・・
いや、そのうちやってみますけどね。


そういえば、Code Formula、時間はかかったのもも、B問題が綺麗に解けたので、コードを貼っておきます。
Pascalは配列の添え字の範囲、もっと言うと型も(順序型ならOK)自由に決められるので、それが活きました。いえーい。

program solve(input, output);
 
var
pin : array[0..9] of Char;
i : Integer;
inp1, inp2 : Integer;
loop1, loop2 : Integer;
keepnum : Integer;
begin
 
read(inp1);
readln(inp2);
for i := 0 to 9 do
pin[i] := 'x';
 
for loop1 := 1 to inp1 do
begin
	read(keepnum);
	pin[keepnum] := '.'
end;
 
 
for loop2 := 1 to inp2 do
begin
	read(keepnum);
	pin[keepnum] := 'o'
end;
 
writeln(pin[7],' ',pin[8],' ',pin[9],' ',pin[0]);
writeln(' ',pin[4],' ',pin[5],' ',pin[6]);
writeln('  ',pin[2],' ',pin[3]);
writeln('   ',pin[1]);
	
end.

まぁ配列の添え字が0から始まる言語だったら同じように書けるのですが。
たとえピンの番号の表し方が0〜9であろうと1〜10であろうとA〜Jであろうと、Pascalなら同じ綺麗さで書けるってことです。
今のところ見つけた、唯一?のPascalの優位性です。

長くなってしまいました。今回は以上です。