Advertisement
Guest User

課題4

a guest
May 23rd, 2019
87
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 6.58 KB | None | 0 0
  1.  
  2. /*--------------------------------------------------kadai4.c--------------------------------------------------*/
  3.  
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <unistd.h>
  7.  
  8. #include "myrandom.h" /*stdbool.hはmyrandom.hで宣言済み*/
  9.  
  10. static bool flag_inloop, flag_init;
  11. /*flag_inloop:シュミレーションで使用。初めてキャラを引いたかどうかを判別。デフォルトはfalse(=0)*/
  12. /*flag_init:初期設定で使用。trueの場合線形合同法となる。デフォルトはfalse*/
  13.  
  14. double rate = 0.0005; /*排出率。 100倍した値が確率になる*/
  15. unsigned yen = 100, count = 10000, width = 5, width_money;
  16. unsigned long long used_money;
  17. /*yen:一回ガチャを引くのにかかる金額, count:試行回数, width:度数分布の幅,
  18.  used_money:使った金額, width_money:値段の区間幅*/
  19. /*宣言されていなければ上記初期パラメータを使用*/
  20.  
  21. /*どの金額帯で引けたかを探索*/
  22. unsigned long long compare(void) {
  23.     const unsigned long long width_max = 0x1FFFD19B7DF000; /*width_max = 9,007,000,000,000*/
  24.     unsigned long long i, j;
  25.     for (i = 0, j = 0; i <= width_max - width_money; i += width_money, j++)
  26.         if (i <= used_money&&used_money < i + width_money) return j;
  27.     /*iがwidth_max-width_moneyに達するか、used_moneyが区間幅(i以上(i+width_money)未満)までループ*/
  28.     /*jは配列hitの要素番号を返す。iが増加するたびにjも増える*/
  29.     return j;
  30. }
  31.  
  32. /*ガチャシュミレーター*/
  33. void pickup(void) {
  34.     const unsigned array_max = 0x7FFFFFFF, ceil_max = 0x3B9ACA00;
  35.     /*array_max=2,147,483,647=2^32-1(int型の最大値)、ceil_max=1,000,000,000(試行できる最大回数)*/
  36.     /*constは上書き禁止の意味*/
  37.     static unsigned hitcount; /*当たった回数(平均で使用)*/
  38.     static unsigned long long total; /*金額の総和(平均で使用)*/
  39.     int i, j, min, max, avg;
  40.     int *hit;
  41.     unsigned long long t;
  42.  
  43.     /*↓シュミレーション開始↓*/
  44.     hit = (int *)calloc(array_max, sizeof(int));
  45.     /*各金額幅で引いた回数を格納。OSによっては実行時にsegmentation faultが出るので、
  46.      その場合は第一引数を10億くらい(=ceil_max)に値を変えればok*/
  47.     width_money = width * count;
  48.     for (i = 0; i < count; i++) {
  49.         for (j = 0; j < ceil_max; j++) {
  50.             if (my_urand_f(flag_init) <= rate) { /*my_urand_fが返す値がrate以下の場合*/
  51.                 used_money = (j + 1)*yen; /*used_moneyにかかった金額を格納。0円になるのを防ぐ為にjに1加算してある*/
  52.                 if (!flag_inloop) { /*min,maxの初期値*/
  53.                     min = max = used_money;
  54.                     flag_inloop = true;
  55.                 }
  56.                 else { /*最小、最大値の比較*/
  57.                     if (min > used_money) min = used_money;
  58.                     else if (max < used_money) max = used_money;
  59.                 }
  60.                 if ((t = compare()) > array_max) { /*区間幅の個数がint型の最大値を超えた場合(スタックオーバーフロー回避)*/
  61.                     printf("Stack overflow\n");
  62.                     free(hit);
  63.                     exit(EXIT_FAILURE);
  64.                 }
  65.                 else hit[t] ++;
  66.                 hitcount++;
  67.                 total += used_money;
  68.                 break;
  69.             }
  70.         }
  71.     }
  72.  
  73.     /*出力処理*/
  74.     FILE *output;
  75.     output = fopen("data.txt", "w");
  76.  
  77.     avg = total / hitcount;
  78.     printf("------------------------------------------------------------------------------------\n");
  79.     printf("Result:\nMin=%dyen, Max=%dyen, Avg=%dyen\n", min, max, avg);
  80.     for (i = 0, j = 0; hit[j] != 0; i += width, j++) { /*配列hitのj番目が0であるまでループ*/
  81.         printf("%7d-%7d %7d\n", i*count, (i + width)*count, hit[j]);
  82.         fprintf(output, "%d- %d\n", i, hit[j]);
  83.     }
  84.     printf("------------------------------------------------------------------------------------\n");
  85.     fclose(output);
  86.     free(hit);
  87. }
  88.  
  89. /*初期設定*/
  90. void initialize(int argc, char **argv) {
  91.     int b;
  92.     char c;
  93.  
  94.     /*コマンドラインの因数を判別*/
  95.     while ((b = getopt(argc, argv, "r:y:c:w:")) != -1) {
  96.         switch (b) {
  97.         case 'r':
  98.             rate = atof(optarg) / 100.0;
  99.             break;
  100.         case 'y':
  101.             yen = atoi(optarg);
  102.             break;
  103.         case 'c':
  104.             count = atoi(optarg);
  105.             break;
  106.         case 'w':
  107.             width = atoi(optarg);
  108.             break;
  109.         default:
  110.             printf("Unknown command:%c\n", b);
  111.             exit(EXIT_FAILURE);
  112.         }
  113.     }
  114.  
  115.     /*初期パラメータを出力*/
  116.     printf("------------------------------------------------------------------------------------\n");
  117.     printf("Parameter:\n        Rate:%.3f%%, $:%dyen, Count:%d, Width:%d, Type:", rate*100, yen, count, width);
  118.  
  119.     /*乱数生成法の選択*/
  120. #ifdef MT /*メルセンヌツイスタ(64bit)*/
  121.     mt_initialize(); /*乱数の初期化*/
  122.     printf("MT\n");
  123. #else /*線形合同法(パラメータはANSI Cより)*/
  124.     flag_init = true;
  125.     printf("LGCs(ANSI C)\n");
  126. #endif
  127. }
  128.  
  129. int main(int argc, char **argv)
  130. {
  131.     initialize(argc, argv);
  132.     pickup();
  133.     return 0;
  134. }
  135.  
  136. /*--------------------------------------------------myrandom.c--------------------------------------------------*/
  137. #include "myrandom.h"
  138. #include "MT64.h" /*メルセンヌツイスタ生成用のヘッダファイル*/
  139.  
  140. const static unsigned long m = 0x80000000; /*線形合同法の周期*/
  141.  
  142. void mt_initialize(void) { /*メルセンヌツイスタ生成のための初期化*/
  143.     init_genrand64(SIGNIFICAND_64);
  144. }
  145.  
  146. double my_urand(void) { /*線形合同法のみ使用。区間[0,2147483628]内の一様乱数を生成*/
  147.     const unsigned a = 1103515245, c = 12345;
  148.     static int param_x;
  149.  
  150.     param_x = (a * param_x + c) % m;
  151.     return (double)param_x;
  152. }
  153.  
  154. double my_urand_f(bool flag) {
  155.     return !flag ? (genrand64_int64() >> 11) / 9007199254740992.0 : my_urand() / (double)m;
  156.     /*flagがfalse:区間[0,1]でのメルセンヌツイスタの乱数を戻り値に指定
  157.       〃   true:区間[0,1]での線形合同法の乱数を戻り値に指定*/
  158.     /*メルセンヌツイスタ:genrand64_int64で乱数を生成、その値を11bitシフトして2^64-1で割った値を戻り値にする*/
  159. }
  160.  
  161. /*--------------------------------------------------myrandom.h--------------------------------------------------*/
  162. #ifndef myrandom_h /*kadai4.cとmyrandom.hでこのヘッダを定義している為、コンパイルエラー回避のために設置*/
  163. #define myrandom_h
  164.  
  165. #include <stdbool.h> /*boolean*/ /*bool型を定義できるようにする。true=1,false=0*/
  166.  
  167. #define SIGNIFICAND_64 0x1FFFFFFFFFFFFFULL
  168. /*SIGNIFICAND_64=9,007,199,254,740,991=2^53-1。64bitでの演算の精度は2^53-1まで保たれる*/
  169.  
  170. void mt_initialize(void); /*メルセンヌツイスタの初期化*/
  171. double my_urand(void); /*一様乱数を生成(線形合同法)*/
  172. double my_urand_f(bool flag); /*一様乱数を正規一様乱数に変換(区間[0,1])*/
  173.  
  174. #endif
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement