Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*--------------------------------------------------kadai4.c--------------------------------------------------*/
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include "myrandom.h" /*stdbool.hはmyrandom.hで宣言済み*/
- static bool flag_inloop, flag_init;
- /*flag_inloop:シュミレーションで使用。初めてキャラを引いたかどうかを判別。デフォルトはfalse(=0)*/
- /*flag_init:初期設定で使用。trueの場合線形合同法となる。デフォルトはfalse*/
- double rate = 0.0005; /*排出率。 100倍した値が確率になる*/
- unsigned yen = 100, count = 10000, width = 5, width_money;
- unsigned long long used_money;
- /*yen:一回ガチャを引くのにかかる金額, count:試行回数, width:度数分布の幅,
- used_money:使った金額, width_money:値段の区間幅*/
- /*宣言されていなければ上記初期パラメータを使用*/
- /*どの金額帯で引けたかを探索*/
- unsigned long long compare(void) {
- const unsigned long long width_max = 0x1FFFD19B7DF000; /*width_max = 9,007,000,000,000*/
- unsigned long long i, j;
- for (i = 0, j = 0; i <= width_max - width_money; i += width_money, j++)
- if (i <= used_money&&used_money < i + width_money) return j;
- /*iがwidth_max-width_moneyに達するか、used_moneyが区間幅(i以上(i+width_money)未満)までループ*/
- /*jは配列hitの要素番号を返す。iが増加するたびにjも増える*/
- return j;
- }
- /*ガチャシュミレーター*/
- void pickup(void) {
- const unsigned array_max = 0x7FFFFFFF, ceil_max = 0x3B9ACA00;
- /*array_max=2,147,483,647=2^32-1(int型の最大値)、ceil_max=1,000,000,000(試行できる最大回数)*/
- /*constは上書き禁止の意味*/
- static unsigned hitcount; /*当たった回数(平均で使用)*/
- static unsigned long long total; /*金額の総和(平均で使用)*/
- int i, j, min, max, avg;
- int *hit;
- unsigned long long t;
- /*↓シュミレーション開始↓*/
- hit = (int *)calloc(array_max, sizeof(int));
- /*各金額幅で引いた回数を格納。OSによっては実行時にsegmentation faultが出るので、
- その場合は第一引数を10億くらい(=ceil_max)に値を変えればok*/
- width_money = width * count;
- for (i = 0; i < count; i++) {
- for (j = 0; j < ceil_max; j++) {
- if (my_urand_f(flag_init) <= rate) { /*my_urand_fが返す値がrate以下の場合*/
- used_money = (j + 1)*yen; /*used_moneyにかかった金額を格納。0円になるのを防ぐ為にjに1加算してある*/
- if (!flag_inloop) { /*min,maxの初期値*/
- min = max = used_money;
- flag_inloop = true;
- }
- else { /*最小、最大値の比較*/
- if (min > used_money) min = used_money;
- else if (max < used_money) max = used_money;
- }
- if ((t = compare()) > array_max) { /*区間幅の個数がint型の最大値を超えた場合(スタックオーバーフロー回避)*/
- printf("Stack overflow\n");
- free(hit);
- exit(EXIT_FAILURE);
- }
- else hit[t] ++;
- hitcount++;
- total += used_money;
- break;
- }
- }
- }
- /*出力処理*/
- FILE *output;
- output = fopen("data.txt", "w");
- avg = total / hitcount;
- printf("------------------------------------------------------------------------------------\n");
- printf("Result:\nMin=%dyen, Max=%dyen, Avg=%dyen\n", min, max, avg);
- for (i = 0, j = 0; hit[j] != 0; i += width, j++) { /*配列hitのj番目が0であるまでループ*/
- printf("%7d-%7d %7d\n", i*count, (i + width)*count, hit[j]);
- fprintf(output, "%d- %d\n", i, hit[j]);
- }
- printf("------------------------------------------------------------------------------------\n");
- fclose(output);
- free(hit);
- }
- /*初期設定*/
- void initialize(int argc, char **argv) {
- int b;
- char c;
- /*コマンドラインの因数を判別*/
- while ((b = getopt(argc, argv, "r:y:c:w:")) != -1) {
- switch (b) {
- case 'r':
- rate = atof(optarg) / 100.0;
- break;
- case 'y':
- yen = atoi(optarg);
- break;
- case 'c':
- count = atoi(optarg);
- break;
- case 'w':
- width = atoi(optarg);
- break;
- default:
- printf("Unknown command:%c\n", b);
- exit(EXIT_FAILURE);
- }
- }
- /*初期パラメータを出力*/
- printf("------------------------------------------------------------------------------------\n");
- printf("Parameter:\n Rate:%.3f%%, $:%dyen, Count:%d, Width:%d, Type:", rate*100, yen, count, width);
- /*乱数生成法の選択*/
- #ifdef MT /*メルセンヌツイスタ(64bit)*/
- mt_initialize(); /*乱数の初期化*/
- printf("MT\n");
- #else /*線形合同法(パラメータはANSI Cより)*/
- flag_init = true;
- printf("LGCs(ANSI C)\n");
- #endif
- }
- int main(int argc, char **argv)
- {
- initialize(argc, argv);
- pickup();
- return 0;
- }
- /*--------------------------------------------------myrandom.c--------------------------------------------------*/
- #include "myrandom.h"
- #include "MT64.h" /*メルセンヌツイスタ生成用のヘッダファイル*/
- const static unsigned long m = 0x80000000; /*線形合同法の周期*/
- void mt_initialize(void) { /*メルセンヌツイスタ生成のための初期化*/
- init_genrand64(SIGNIFICAND_64);
- }
- double my_urand(void) { /*線形合同法のみ使用。区間[0,2147483628]内の一様乱数を生成*/
- const unsigned a = 1103515245, c = 12345;
- static int param_x;
- param_x = (a * param_x + c) % m;
- return (double)param_x;
- }
- double my_urand_f(bool flag) {
- return !flag ? (genrand64_int64() >> 11) / 9007199254740992.0 : my_urand() / (double)m;
- /*flagがfalse:区間[0,1]でのメルセンヌツイスタの乱数を戻り値に指定
- 〃 true:区間[0,1]での線形合同法の乱数を戻り値に指定*/
- /*メルセンヌツイスタ:genrand64_int64で乱数を生成、その値を11bitシフトして2^64-1で割った値を戻り値にする*/
- }
- /*--------------------------------------------------myrandom.h--------------------------------------------------*/
- #ifndef myrandom_h /*kadai4.cとmyrandom.hでこのヘッダを定義している為、コンパイルエラー回避のために設置*/
- #define myrandom_h
- #include <stdbool.h> /*boolean*/ /*bool型を定義できるようにする。true=1,false=0*/
- #define SIGNIFICAND_64 0x1FFFFFFFFFFFFFULL
- /*SIGNIFICAND_64=9,007,199,254,740,991=2^53-1。64bitでの演算の精度は2^53-1まで保たれる*/
- void mt_initialize(void); /*メルセンヌツイスタの初期化*/
- double my_urand(void); /*一様乱数を生成(線形合同法)*/
- double my_urand_f(bool flag); /*一様乱数を正規一様乱数に変換(区間[0,1])*/
- #endif
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement