SHARE
TWEET

課題4

a guest May 23rd, 2019 70 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  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
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
Not a member of Pastebin yet?
Sign Up, it unlocks many cool features!
 
Top