- ベストアンサー
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; } 宜しくお願い致します。
- みんなの回答 (7)
- 専門家の回答
質問者が選んだベストアンサー
質問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;
その他の回答 (6)
- karyn
- ベストアンサー率0% (0/7)
Karynです。 ちなみに一箇所だけバグを入れてあるのは全てを教えちゃいけないという親心です。 実行結果を見るとすぐに判ると思いますよ。
お礼
karynさん有難うございました。 無事にデータを作成することができました。
- karyn
- ベストアンサー率0% (0/7)
視点を変えてこんなのはどうでしょう? #!/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日になったやつはもう一度やり直す。 どんな範囲の日付も簡単に作り出せますよ。 これがスマートなアルゴリズムというやつです。
- Dpop
- ベストアンサー率51% (279/544)
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++; }
お礼
Dpopさん、ご回答有難うございました。 大変助かりました。
- edomin
- ベストアンサー率32% (327/1003)
#1です。もう一度・・・ 条件判断は、 if($month_rand>9){print "0";} と、 if($day_rand>9){print "0";} で良いかと・・・ (それぞれを、月と日付のprint文の前に挿入する。)
- edomin
- ベストアンサー率32% (327/1003)
#1です。間違えました。 $year_rand=int(rand(1.9))+4; こっちの方が良いかと。 0~1.9までの乱数を発生させて整数化するので0か1しか出来ません。それに4を加えてやる。 「日付については、条件判断で、」 月についても、条件判断で・・・
- edomin
- ベストアンサー率32% (327/1003)
04と05に限定するなら、 $year_rand=int(rand(2))+3; で強制的に1か2を発生させて、3を加えれば良いかと。 日付については、条件判断で、9以下なら print "0$day_rand,"; 10以上なら print "$day_rand,"; で出来ませんか?
お礼
leaz024さん明快なご回答有難うございました。 大変助かりました。