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

投稿

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 IO => ':utf8'; # -CD -CA@ARGVの内容にUTF-8フラグを立てます。コ…

Project Euler - Problem 43

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

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 = t10. 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 = t10である. 単語の値が三角数であるとき, その単語を三角語と呼ぶ.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; } open my $words, '<', 'words.txt&#…

Project Euler - Problem 41

問題原文What is the largest n-digit pandigital prime that exists?日本語訳n桁のPandigitalな素数の中で最大の数を答えよ.解答ある数が3の倍数のとき、その各桁を足し合わせた数もまた3の倍数であり、その逆もいえます:n = am-1am-2...a0
= am-1×10m-1 + am-2×10m-2 + ... + a0×100
= am-1×(1 + 999...9) + am-2×(1 + 99...9) + ... + a1×(1 + 9) + a0×1
= (am-1 + am-2 + ... + a0) + am-1×(999...9) + am-2×(99...9) + ... + a1×9
∴ nが3の倍数のとき、am-1 + am-2 + ... + a0は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 .. sqrt $n; } my $prime_tails = set(1, 3, 7, 9); sub max_pandigital_prime($;$$); sub max…

Project Euler - Problem 40

問題原文An irrational decimal fraction is created by concatenating the positive integers:0.123456789101112131415161718192021...It can be seen that the 12th digit of the fractional part is 1.If dn represents the nth digit of the fractional part, find the value of the following expression.d1 × d10 × d100 × d1000 × d10000 × d100000 × d1000000日本語訳正の整数を順に連結して得られる以下の10進の無理数を考える:0.123456789101112131415161718192021...小数点第12位は1である.dnで小数点第n位の数を表す. d1 × d10 × d100 × d1000 × d10000 × d100000 × d1000000 を求めよ.解答数列作って、繋げて、取り出して、掛け合わせる。おしまい。#!/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です。三平方の定理よりa2 + b2 = c2で、p = a + b + c ⇒ c = p - (a + b)なので、cを消去して:a2 + b2 = (p - (a + b))2 = p2 - 2p(a + b) + a2 + 2ab + b2よってp2 - 2p(a + b) + 2ab = 0であり、a、bが解のときpは偶数であることが分かります。 またこれをbについて解くとb = (2ap - p2) / 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 @solutions; for my $i (1 .. $p - 1) { my $j = ($p * (2 * $i - $p)) / (2 * ($i - $p)); …