こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

Perlの乱数について

RedHat Linux ES2.1のperl v5.6.1にて初めてのプログラムを書いているものです。
Oracle9iに格納するDATE型のデータを大量に乱数にて作成しようとしているのですが、うまくいきません。

作成しようとしているのは2004年度か2005年度のある日付です(30日まで)。
例)
04-01-30
05-07-12
04-09-28
04-12-11

質問1.下のプログラムだと、年度が00,01,02,03,04,05の値をとり得てしまう。これを04か05に限定するにはどうすればよいか。

質問2.月・日が1桁の場合は0を頭につけたい。下のプログラムでは05-12-1となったり04-5-30となったりしてしまう。

#!/usr/bin/perl

$a = 1;

while($a < 100000){

$year_rand = int(rand(5));
$month_rand = int(rand(12))+1;
$day_rand = int(rand(30))+1;

print "0$year_rand-";
print "$month_rand-";
print "$day_rand,";
print "\n";

$a = $a+1;

}

宜しくお願い致します。

投稿日時 - 2004-07-13 18:36:19

QNo.925117

暇なときに回答ください

質問者が選んだベストアンサー

質問1について
$r = int(rand(N)) では、0≦$r<N という範囲で乱数が発生しますので、
> これを04か05に限定する
には、その振れ幅である2を指定し(0か1が発生する)、最低値である4を足せばよいことになります。
つまり、
$year_rand = int(rand(2)) + 4;

質問2について
このような場合は printf が便利です。
printf では出力形式を指定することができ、2桁で頭を0埋めして出力、なども簡単にできます。

4行のprint文の代わりに、次のようにしてみてください。
printf "%02d-%02d-%02d,\n", $year_rand, $month_rand, $day_rand;

投稿日時 - 2004-07-13 19:17:11

お礼

leaz024さん明快なご回答有難うございました。
大変助かりました。

投稿日時 - 2004-07-23 09:39:32

ANo.5

このQ&Aは役に立ちましたか?

5人が「このQ&Aが役に立った」と投票しています

回答(7)

ANo.7

Karynです。
ちなみに一箇所だけバグを入れてあるのは全てを教えちゃいけないという親心です。
実行結果を見るとすぐに判ると思いますよ。

投稿日時 - 2004-07-16 00:44:52

お礼

karynさん有難うございました。
無事にデータを作成することができました。

投稿日時 - 2004-07-23 09:38:37

ANo.6

視点を変えてこんなのはどうでしょう?

#!/usr/bin/perl

require "timelocal.pl";

$time20040101=&timelocal(0,0,0,1,0,104);
$time20051231=&timelocal(59,59,23,31,11,105);

for(1..100)
{
$time=$time20040101+int(rand($time20051231-$time20040101));
($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)=localtime($time);
if($mday>30) continue;
printf("%02d-%02d-%02d\n",$year,$mon+1,$mday);
}

要約すると以下のとおりです。
timelocal.plというシステム関数を使います。

2004/01/01から2005/12/31までの日付を秒数に変換して、その差を乱数に与えます。
そうすると2年間のどこかの秒が得られます。
得られた乱数を2004/01/01の秒数に加えて得られた秒数をもう一度日付に変換します。
日が31日になったやつはもう一度やり直す。

どんな範囲の日付も簡単に作り出せますよ。
これがスマートなアルゴリズムというやつです。

投稿日時 - 2004-07-16 00:26:23

ANo.4

rand は rand(作りたい数) を与えます。ここでは、04と05 の2つのなので、2が入ります。
しかし、これでは0と1しか返って来ないので、ゲタを履かせます。それが+3です。

表示部分ですが、printf 関数を利用してしまった方が簡単でしょう。
多少、処理速度は落ちますが、あまり気にするほどの物でもありません。(中身は、C の printf です。)

\- は、- をマイナス記号と判定されない様に\を入れましたが、必要ないかも知れません(^_^;;)

$a = $a + 1;

は、

$a++;

の方が微妙にですが効率が良いです。


#!/usr/bin/perl

$a = 1;

while($a < 100000){

$year_rand = int(rand(2))+3;
$month_rand = int(rand(12))+1;
$day_rand = int(rand(30))+1;


printf("%02d\-%02d\-%02d\n", $year_rand, $month_rand, $day_rand);

$a++;

}

投稿日時 - 2004-07-13 19:11:31

お礼

Dpopさん、ご回答有難うございました。
大変助かりました。

投稿日時 - 2004-07-23 09:40:45

ANo.3

#1です。もう一度・・・

条件判断は、
if($month_rand>9){print "0";}
と、
if($day_rand>9){print "0";}

で良いかと・・・
(それぞれを、月と日付のprint文の前に挿入する。)

投稿日時 - 2004-07-13 19:10:44

ANo.2

#1です。間違えました。

$year_rand=int(rand(1.9))+4;
こっちの方が良いかと。
0~1.9までの乱数を発生させて整数化するので0か1しか出来ません。それに4を加えてやる。
「日付については、条件判断で、」
月についても、条件判断で・・・

投稿日時 - 2004-07-13 19:06:12

ANo.1

04と05に限定するなら、
$year_rand=int(rand(2))+3;
で強制的に1か2を発生させて、3を加えれば良いかと。
日付については、条件判断で、9以下なら
print "0$day_rand,";
10以上なら
print "$day_rand,";
で出来ませんか?

投稿日時 - 2004-07-13 18:57:35

あなたにオススメの質問