• ベストアンサー

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; } 宜しくお願い致します。

  • Perl
  • 回答数7
  • ありがとう数8

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

  • ベストアンサー
  • leaz024
  • ベストアンサー率75% (398/526)
回答No.5

質問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;

rio_grande
質問者

お礼

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

その他の回答 (6)

  • karyn
  • ベストアンサー率0% (0/7)
回答No.7

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

rio_grande
質問者

お礼

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

  • karyn
  • ベストアンサー率0% (0/7)
回答No.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日になったやつはもう一度やり直す。 どんな範囲の日付も簡単に作り出せますよ。 これがスマートなアルゴリズムというやつです。

  • Dpop
  • ベストアンサー率51% (279/544)
回答No.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++; }

rio_grande
質問者

お礼

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

  • edomin
  • ベストアンサー率32% (327/1003)
回答No.3

#1です。もう一度・・・ 条件判断は、 if($month_rand>9){print "0";} と、 if($day_rand>9){print "0";} で良いかと・・・ (それぞれを、月と日付のprint文の前に挿入する。)

  • edomin
  • ベストアンサー率32% (327/1003)
回答No.2

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

  • edomin
  • ベストアンサー率32% (327/1003)
回答No.1

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

関連するQ&A

  • これまた初歩的なことかもしれませんが^^;

    Cです。今作成中の、カレンダーを表示させるプログラムの一部なのですが、それを以下に書きます。 ――――――――――――――― int day_of_week(int year, int month, int day) { int a, i, days1 = 0, days2 = 0, alldays, wk; a = (year - 1)/4; days1 = a * 366 + (year - 1 - a)*365 - (year - 1)/100 + (year - 1)/400; for(i=1; i< month ; i++) days2 += day_of_month(year, i); alldays = days1 + days2 + day; wk = alldays % 7; return(wk); } int write_cal(int year, int month) { /* !!! */ } ――――――――――― 関数write_calで、関数day_of_weekの戻り値wkをつかいたいのですが、!!! にそのままday_of_week(int year, int month, int day)を入れると当然コンパイルエラーになります。初歩的なことをわすれているのかもしれませんが、ポインタなどもつかっていいのでやりかた教えてください! int write_cal(int year, int month, int day) にするというのはナシでお願いします

  • プログラムの内容

    以下のプログラムは答えとして渡されたものなんですが、 コマンド引数を使ったプログラムの流れがよくわかりません。 簡単に解説してくれる方、いませんか? #include <stdio.h> int leapyear(int year){ if(year%400 == 0) return 1; else if(year%4 == 0 && year%100 != 0) return 1; else return 0; } void addmonth(int *day, int *month, int *year){ *day = 1; (*month)++; if(*month > 12) { *month = 1; (*year)++; } } int main(int argc, char *argv[]){ int year, month, day, a=0, max_days; int month_days[12] = {31,28,31,30,31,30,31,31,30,31,30,31}; if(argc < 2) max_days = 10000; else max_days = atoi(argv[1]); printf("今日は西暦何年 何月 何日? "); scanf("%d%d%d",&year,&month,&day); while(a<max_days) { a++; day++; if(month == 2 && leapyear(year)) { if(day > 29) addmonth(&day, &month, &year); } else { if(day > month_days[month-1]) addmonth(&day, &month, &year); } } printf("今日から%d日後は、%d年%d月%d日です。",max_days, year, month, day); }

  • 乱数について・・・

    (1)1,2,3,4の整数のどれかを乱数で発生させる方法 (2)0~1までの実数を発生させる方法 を教えていただけないでしょうか?(a.outするたびに値が変わってほしいです。) ※一応、下のプログラムにあるように実行するたびに違う乱数がanswerに入るようにはできたのですが、いまいち理解できていません。軽い説明や参考URLなども教えてもらえたら助かります。 よろしくお願いします。 #include<time.h> int main() { unsigned short time_a,time_b; unsigned long answer; time_a = time(NULL); time_b = time_a; srand(time_b); answer = rand(); printf("答えは = %d\n",answer); }

  • メルセンヌツイスターによる乱数の使い方

    メルセンヌツイスターによる乱数を生成したいのですが、下記コードにすると、mt_rand関数を呼ぶたびにシードが初期化され他乱数が生成されます。 やりたいことは、main関数で一度シード101で初期化した後は、mt_rand関数内では、初期化することなく継続した乱数を生成したいのです。 そのためa_mt_rand関数のようにすると、mtが定義されていないとなるエラーとなります。 namespaceの問題と思うのですが、色々試してみましたが、できませんでした。 どのようにすればできるでしょうか。 vc++11、windows11 使用 参考サイト C++ 乱数ライブラリ std::random の使い方 リンクはうまく貼れませんでした。 #pragma hdrstop #include <iostream> #include <stdio.h> #include <random> using namespace std; void mt_rand(void); int main(int argc, char *argv[]) { int ptr; std::mt19937 mt(101); // メルセンヌツイスターの32ビット版、引数は初期シード std::uniform_int_distribution <> rand100(0, 100); // [0, 99] 範囲の一様乱数 ptr = rand100(mt); printf("ptr=%d\n",ptr); mt_rand(); } void mt_rand(void) { int ptr=0; std::mt19937 mt(101); // メルセンヌツイスターの32ビット版、引数は初期シード std::uniform_int_distribution <> rand100(0, 100); // [0, 99] 範囲の一様乱数 ptr = rand100(mt); printf("%d\n",ptr); } void a_mt_rand(void) { int ptr=0; ptr = rand100(mt); printf("%d\n",ptr); }

  • 乱数について

    乱数の分布を見るために以下のようなプログラムを書きました。 #include <stdio.h> #include <stdlib.h> #include <math.h> int main() { int i,imax, S[RAND_MAX], r; double x,y; FILE *output1; output1=fopen("random2.data","w"); imax=100000; for(i=0;i<=imax;i++){ r = rand(); S[r] += 1; } for(i=0;i<=RAND_MAX;i++){ fprintf(output1,"%d %d \n",i,S[i]); } return 0; } するとコンパイルできて実行もできるのですが、なぜか乱数が30000を 超えるくらいのところでおかしな値になりました。 原因がわからないのでどなたか教えてください。

  • 乱数を更新するキーはありますか。

    W7, 0ffice2003 です。 ただいま、小倉百人一首の練習プログラムをつくっています。EXcelを使うつもりですが、int(rand()*100)で1~100の乱数を作って歌番号にあわせます。このとき、次の一首に進むのに 新たな乱数を作る必要がありますが、キーを操作する程度で乱数を変更する方法がありましたら 教えてください。お願いします。

  • 乱数発生

    #include <stdio.h> #include <stdlib.h> #include <time.h> int main(void) {int y, m, l; srand( (unsigned)time( NULL ) ); y=rand() % 2500 + 1600; m=rand() % 12 + 1; l=rand() % 29 + 1; printf("西暦%d年%d月%d日",y,m,l); return(0); }今回は乱数発生でランダムにだされた西暦年月日をつくりましたが、y=rand() % 2500 + 1600; というのがありこれはyという乱数が2500以下1600以上という意味なのですがなぜかプログラムを実行しても3000いくつとか4000いくつなんてのもでてきます。m=rand() % 12 + 1;はちゃんと12以下1以上でできるのですがなぜですか?本当にわかりません。是非だれか教えてください。

  • 乱数の取得

    キー操作をした時に複数の乱数を習得させようと思っています。 【キ─操作関数】  int num[3] = {11, 22, 33}; ←初期化のため数字は適当です。  srand((unsigned int)time(NULL))  for(int i=0; i<=3; i++)  {   num[i] = rand % 10;  } 上記のプログラムを書いています。 num[0]、num[1]、num[2]にそれぞれ0~9の乱数が入ると思うのですが、 num[0]にしか乱数が入りません。 num[1]、num[2]には同じ数字(恐らくtimeで取得した数字?)が入っています。 何かお気づきの点がありましたらアドバイスお願い致します。

  • 0 からa-1 までの整数の乱数をn 個発生させ、発生した整数のヒスト

    0 からa-1 までの整数の乱数をn 個発生させ、発生した整数のヒストグラムをプリントアウトしたいです.また,a とnはコマンドラインから引き渡します 0 からa-1 までの整数を発生する乱数の書き方は (int)((double)rand()/((double)RAND_MAX+1) *a); プログラムをRandHist としたとき RnadHist 10 1000 と入力すれば 0 982 1 1035 2 956 3 1102 ・ ・ 9 971 などと。出力されるようなプログラムを作る問題ですが,a とn は、任意に変えられるように したいです. どなたか教えてください.

  • 標準正規分布の乱数

    RAND()関数は ((double)rand() / (1.0 + RAND_MAX))と定義します。 中心極限定理により、一様乱数を足し合わせると正規分布に近づくことから、 x = 分散 * (Σ[1~12]RAND() - 6) + 平均 で正規乱数が作れる。標準正規分布は分散1、平均0なのでその乱数は x = Σ[1~12]RAND() - 6 ですよね。この乱数を例えば100個羅列するにはどうしたらいいのでしょうか? もし間違ってたら指摘してください。 参考文献「Cによるシミュレーションプログラム 石川宏」 #include <stdio.h> #include <stdlib.h> #define RAND() ((double)rand() / (1.0 + RAND_MAX)) #define NUMBER 10000 /* 発生させる乱数の数 */ main(void) { int j; double u, x; srand(5); for (j = 0; j <= 11; j++) { u = u + RAND(); } x = u - 6.0; }

専門家に質問してみよう