Math Battle [ 0340: 素数日プログラム ]

[ 0340: 素数日プログラム ]


[ 三方万理先生 (algorithm teacher) の出題 ]

1900 年から 2045 年までの間の指定された年に対して、
その年に存在する素数日 (prime dates) を全て列挙するプログラムを書いてください。
実行結果例も添えて。

なお素数日とは年月日を yyyymmdd 形式の 8 桁の整数で表記したとき、
その数が素数であるような日付のことでしたね。
0188 で一度やりましたが、
「うるう年判定」もちゃんといれてください。


[ 井伊莞爾君の回答 ]

多絵さんの素数判定も参考にして書いてみました。
$year_min と $year_max を変えれば対応できる年の範囲は自由に拡張できます。

#!/usr/local/bin/perl

$year_min = 1900;
$year_max = 2045;
@primes = ();
$n_primes = 0;

my $year = accept_year();
prepare_primes($year);
find_prime_dates($year);

sub accept_year() {
 my $line, $year = 0;

 while ($year < $year_min || $year > $year_max) {
  printf("素数日を探す年 (%d〜%d) を入力してください。\n",
   $year_min, $year_max);
  $line = <STDIN>;
  $year = $1 if ($line =~ /^\s*(\d{4})/);
 }
 return $year;
}
sub prepare_primes($year) {
 my ($year) = @_;
 my $i;
 my $max = sqrt($year * 10000 + 1231);

 for ($i=2; $i<=$max; $i++) {
  next unless is_prime($i);
  $primes[$n_primes++] = $i;
 }
}
sub is_prime {
 my $n = shift;
 my $j;

 return 1 if ($n == 2); # true

 for ($j=0; $j<$n_primes; $j++) {
  last if ($n < $primes[$j]**2);
  if (($n % $primes[$j]) == 0) {
   return 0; # false
  }
 }
 return 1; #true
}
sub find_prime_dates($year) {
 my ($year) = @_;
 my @m_days = ();
 my $mm, $dd, $date;
 my $prime_dates = ();
 my $n_prime_dates = 0;
 my $j;

 @m_days
  = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
 if ($year % 100 == 0) {
  $m_days[1] = 29 if ($year % 400 == 0);
 } else {
  $m_days[1] = 29 if ($year % 4 == 0);
 }

 for ($mm=1; $mm<=12; $mm++) {
  for ($dd=1; $dd<=$m_days[$mm-1]; $dd++) {
   $date = $year * 10000 + $mm * 100 + $dd;
   if (is_prime($date)) {
    $prime_dates[$n_prime_dates++]
     = sprintf("%4d/%02d/%02d", $year, $mm, $dd);
   }
  }
 }
 printf("%d年には次のように %d個の素数日があります。\n",
  $year, $n_prime_dates);
 for ($j=0; $j<$n_prime_dates; $j++) {
  printf("%s\n", $prime_dates[$j]);
 }
}

2020 年を指定して実行しました。


$ perl prime_dates.pl
素数日を探す年 (1900〜2045) を入力してください。
2020
2020年には次のように 25個の素数日があります。
2020/01/09
2020/01/11
2020/01/21
2020/01/23
2020/02/23
2020/03/09
2020/04/29
2020/05/11
2020/05/29
2020/06/13
2020/06/19
2020/07/03
2020/07/11
2020/07/21
2020/07/23
2020/07/29
2020/08/01
2020/08/13
2020/09/03
2020/10/21
2020/10/29
2020/11/01
2020/11/13
2020/12/27
2020/12/31


[ 三方万理先生のコメント ]

莞爾君、ありがとうございます。
これでいいみたいですね。
ほかのかたから何かコメントはありますか。


[ 広世正憲君のコメント ]

先を越されてしまいました。

僕が最初に 0188 に取り組んだときとくらべて随分レベルアップしましたね。
うまくサブルーチン分けができていると思います。
指定された年にあわせて除数とする素数集合を用意する際と、
個々の素数日判定の両方に同じ is_prime 関数を使っているところなど。
当然といえば当然ですが。

[ 0341: 次の記事 ]

[ 0340: 素数日プログラム ]

[ 0339: emirp 探し ]

[ 0338: 0331の解きなおし ]

[ 0337: ubuntu 20.04 へ upgrade ]

[ 0336: πの近似計算 ]

[ 0335: 0253 の振り返り ]

[ 0334: Data Camp Python ]

[ 0333: 原始ピタゴラス数をさがす ]

[ 0332: LaTex の使いかた ]

[ 0331: 青い三角形の面積 ]

[ 0330: 長方形の幅 ]

[ 0329: 三角関数の関数の最大最小 ]

[ 0328: IMO 過去問 9 ]

[ 0327: 1+2+3+...+無限 ]

[ 0326: 2分木 sort も含めた性能比較 ]

[ 0325: 最悪ケースでの sort 比較 ]

[ 0324: 0307の回答 ④ ]

[ 0323: 0307の回答 ③ ]

[ 0322: 0307の回答 ② ]

[ 0321: 0307の回答 ① ]

[ 0320: 前の記事 ]

[ トップページへ ]