1 /** 2 * Copyright: © 2012-2014 Anton Gushcha 3 * License: Subject to the terms of the MIT license, as written in the included LICENSE file. 4 * Authors: NCrashed <ncrashed@gmail.com>, 5 * LeMarwin <lemarwin42@gmail.com>, 6 * Nazgull09 <nazgull90@gmail.com> 7 */ 8 module devol.std.random; 9 10 import std.array; 11 import std.algorithm; 12 import std.random; 13 import std.stdio; 14 import std.math; 15 import std.conv; 16 17 /// Вызов одной из функций с определенным шансом 18 /** 19 * Вызывает один из переданных делегатов в зависимости от распределения 20 * вероятностей. 21 * @note Сумма вероятностей должна быть равна единице! 22 * @param range массив вероятностей выбора итого делегата 23 * @param funcs перечисление делегатов 24 */ 25 void randomRange(T...)(double[] range, T funcs) 26 in 27 { 28 double summ = 0; 29 foreach( val; range ) 30 { 31 summ += val; 32 } 33 assert(abs(summ-1) <= 0.001, text("Сумма вероятностей должна быть равна 1! А не ", summ)); 34 assert(range.length == funcs.length, "Размерности массивов вероятностей и делегатов не совпадают!"); 35 } 36 body 37 { 38 double chance = uniform!"[]"(0.,1.); 39 double begin = 0, end = 0; 40 41 foreach(int i, f; funcs ) 42 { 43 end += range[i]; 44 45 if ( begin < chance && chance <= end ) 46 { 47 return f(); 48 } 49 begin = end; 50 } 51 } 52 53 /// Выбор одного из варианта по набору вероятностей 54 /** 55 * Вызывает функцию и передает ей номер выбранной вероятности. 56 * @note Сумма вероятностей должна быть равна единице! 57 * @param range массив вероятностей 58 * @param funcs перечисление делегатов 59 */ 60 void randomRange(alias T)(double[] range) 61 if(__traits(compiles, "T(0);")) 62 in 63 { 64 double summ = 0; 65 foreach( val; range ) 66 { 67 summ += val; 68 } 69 assert(abs(summ-1) <= 0.001, text("Сумма вероятностей должна быть равна 1! А не ", summ)); 70 } 71 body 72 { 73 double chance = uniform!"[]"(0.,1.); 74 double begin = 0, end = 0; 75 76 foreach(int i, val; range ) 77 { 78 end += val; 79 80 if (begin < chance && chance <= end ) 81 { 82 return T(i); 83 } 84 begin = end; 85 } 86 } 87 88 89 /// Статистический тест randomRange 90 unittest 91 { 92 int count = 500000; 93 double a = 0; 94 double b = 0; 95 96 foreach(i; 1..count) 97 { 98 randomRange([0.5, 0.5], 99 { 100 a++; 101 }, 102 { 103 b++; 104 } 105 ); 106 } 107 a = a/count; 108 b = b/count; 109 assert(abs(a-0.5) <= 0.01, text("randomRange не прошла статистический тест da = ", abs(a-0.5))); 110 assert(abs(b-0.5) <= 0.01, text("randomRange не прошла статистический тест db = ", abs(b-0.5))); 111 }