スキップしてメイン コンテンツに移動

投稿

7月, 2009の投稿を表示しています

Perl - -CスイッチでPerlIOレイヤを操作

要約 マルチバイト文字を扱うワンライナはとりあえず-CSDとでもしておくと安心。 長文 どう書く?org で バイナリクロック のお題に 解答したら 、あの 小飼弾氏 が さらに短くして下さいました 。うはー! perl -CIO -Mutf8 -le 'print for map { $_ = sprintf "%06b", $_; tr/01/□■/; $_ } (localtime)[2,1];' Perl5.8対応(そうか、-lで $\ 出力だった)はともかく-Cスイッチって何ぞや、と思ったのでperldoc perlrun : −C [number/list] The "−C" flag controls some of the Perl Unicode features. 「Perl5.8.1より前はWin32のワイド版APIを使うためのスイッチだったけど、誰も使わなかったから使い回すことにしたよ」とか中々楽しいことが書いてあり、現在はPerlIOレイヤを操作するスイッチになっているそうです。 以下簡単な説明。 -C(I|O|E|S) -C(I|O|E)はそれぞれ標準(入力|出力|エラー出力)のPerlIOレイヤをUTF-8に設定するオプションです。つまり次のコードと等価になります: binmode STDIN, ':utf8'; # -CI binmode STDOUT, ':utf8'; # -CO binmode STDERR, ':utf8'; # -CE また-CSオプションで、これらをまとめて指定できます。 -C(i|o|D) -C(i|o)はそれぞれ読み出し(<)、書き込み(>)用に開くファイルハンドルに適用されるデフォルトのPerlIOレイヤをUTF-8に指定します。-CDは両者の一括指定。それぞれ open プラグマを使った以下のコードと等価です: use open IN => ':utf8'; # -Ci use open OUT => ':utf8'; # -Co use open

Project Euler - Problem 43

問題 原文 Let d 1 be the 1 st digit, d 2 be the 2 nd digit, and so on. In this way, we note the following: d 2 d 3 d 4 =406 is divisible by 2 d 3 d 4 d 5 =063 is divisible by 3 d 4 d 5 d 6 =635 is divisible by 5 d 5 d 6 d 7 =357 is divisible by 7 d 6 d 7 d 8 =572 is divisible by 11 d 7 d 8 d 9 =728 is divisible by 13 d 8 d 9 d 10 =289 is divisible by 17 Find the sum of all 0 to 9 pandigital numbers with this property. 日本語訳 d 1 を1桁目, d 2 を2桁目の数とし, 以下順にd n を定義する. この記法を用いると次のことが分かる. d 2 d 3 d 4 =406は2で割り切れる d 3 d 4 d 5 =063は3で割り切れる d 4 d 5 d 6 =635は5で割り切れる d 5 d 6 d 7 =357は7で割り切れる d 6 d 7 d 8 =572は11で割り切れる d 7 d 8 d 9 =728は13で割り切れる d 8 d 9 d 10 =289は17で割り切れる このような性質をもつ0から9のPandigital数の総和を求めよ. 解答 Problem 41 と同様に Pandigital数 を作るだけです。途中で枝切りして無駄な計算を省いています。 除数を保持する配列は一応定数にしてみました。定数の宣言には標準プラグマに constant がありますが、コードが分かり易い Attribute::Constant というCPANモジュールを使っています。 #!/usr/bin/env perl use strict; use wa

Project Euler - Problem 42

問題 原文 By converting each letter in a word to a number corresponding to its alphabetical position and adding these values we form a word value. For example, the word value for SKY is 19 + 11 + 25 = 55 = t 10 . If the word value is a triangle number then we shall call the word a triangle word. Using words.txt (right click and 'Save Link/Target As...'), a 16K text file containing nearly two-thousand common English words, how many are triangle words? 日本語訳 単語中のアルファベットを数値に変換した後に和をとる. この和を「単語の値」と呼ぶことにする. 例えば SKY は 19 + 11 + 25 = 55 = t 10 である. 単語の値が三角数であるとき, その単語を三角語と呼ぶ. 16Kのテキストファイル word.txt 中に約2000語の英単語が記されている. 三角語はいくつあるか? 解答 42問目! ちょっと拍子抜けするほど簡単です。三角数を片っ端から計算して連想配列に入れておき、文字列の値を計算して照合するだけです。 #!/usr/bin/env perl use strict; use warnings; use feature qw/say/; use List::Util qw/sum/; sub word_value($) { my $offset = ord('A') - 1; sum map { ord($_) - $offset } split //, uc shift; } sub tri_num($) { my $n = shift; $n * ($n + 1) / 2

Project Euler - Problem 41

問題 原文 What is the largest n-digit pandigital prime that exists? 日本語訳 n桁のPandigitalな素数の中で最大の数を答えよ. 解答 ある数が3の倍数のとき、その各桁を足し合わせた数もまた3の倍数であり、その逆もいえます: n = a m-1 a m-2 ...a 0 = a m-1 ×10 m-1 + a m-2 ×10 m-2 + ... + a 0 ×10 0 = a m-1 ×(1 + 999...9) + a m-2 ×(1 + 99...9) + ... + a 1 ×(1 + 9) + a 0 ×1 = (a m-1 + a m-2 + ... + a 0 ) + a m-1 ×(999...9) + a m-2 ×(99...9) + ... + a 1 ×9 ∴ nが3の倍数のとき、a m-1 + a m-2 + ... + a 0 は3の倍数 つまり1 + 2 + ... + mが3の倍数であったとすると、m桁のPandigital数の中に解は存在し得ないことが分かります。m = 8, 9のときがこの場合に該当するので、探索範囲を大きく減らせます。 Pandigital数 を作る際に数値を重複なく選ぶため、 Set::Object というCPANモジュールを使って簡単な集合演算を行っています。 #!/usr/bin/env perl; use strict; use warnings; use feature qw/say state/; use List::Util qw/sum/; use List::MoreUtils qw/none/; use Set::Object qw/set/; sub is_prime($) { state %memos; my $n = shift; return 0 if $n < 2; return 1 if $n == 2; return 1 if $n == 3; return $memos{$n} if exists $memos{$n}; $memos{$n} = none { $n % $_ == 0 } 2 ..

Project Euler - Problem 40

問題 原文 An irrational decimal fraction is created by concatenating the positive integers: 0.123456789101112131415161718192021... It can be seen that the 12 th digit of the fractional part is 1. If d n represents the n th digit of the fractional part, find the value of the following expression. d 1 × d 10 × d 100 × d 1000 × d 10000 × d 100000 × d 1000000 日本語訳 正の整数を順に連結して得られる以下の10進の無理数を考える: 0.123456789101112131415161718192021... 小数点第12位は1である. d n で小数点第n位の数を表す. d 1 × d 10 × d 100 × d 1000 × d 10000 × d 100000 × d 1000000 を求めよ. 解答 数列作って、繋げて、取り出して、掛け合わせる。おしまい。 #!/usr/bin/env perl use strict; use warnings; use feature qw/say/; use List::Util qw/reduce/; my $n = 0; my $str = ''; $str .= $n++ while length $str <= 1_000_000; our ($a, $b); say reduce { $a * $b } map { substr $str, 10 ** $_, 1 } 0 .. 6;

Project Euler - Problem 39

問題 原文 If p is the perimeter of a right angle triangle with integral length sides, {a,b,c}, there are exactly three solutions for p = 120. {20,48,52}, {24,45,51}, {30,40,50} For which value of p ≤ 1000, is the number of solutions maximised? 日本語訳 辺の長さが{a,b,c}と整数の3つ組である直角三角形を考え, その周囲の長さをpとする. p = 120のときには3つの解が存在する: {20,48,52}, {24,45,51}, {30,40,50} p < 1000 で解の数が最大になる p を求めよ. 解答 問題の前提からp = a + b + cです。 三平方の定理よりa 2 + b 2 = c 2 で、p = a + b + c ⇒ c = p - (a + b)なので、cを消去して: a 2 + b 2 = (p - (a + b)) 2 = p 2 - 2p(a + b) + a 2 + 2ab + b 2 よってp 2 - 2p(a + b) + 2ab = 0であり、a、bが解のときpは偶数であることが分かります。 またこれをbについて解くとb = (2ap - p 2 ) / 2(a - p)なので、aの値を定めればbの値は一意に決まることが分かります。 結局各pについてa > bとなるまでaを一通り試すだけで良いことになります。 実のところ答えの3つ組を計算する必要はなかったりしますが、答えを出力した上でその数を数える形にしています。 #!/usr/bin/perl use strict; use warnings; use feature qw/say/; use List::Util qw/reduce/; sub solutions($) { my $p = shift; return () unless $p % 2 == 0; my @solut