一、完全隨機紅包
(一)、方案一:(其實對於金錢應該用decimal,不用double,這里先忽略這個問題只討論算法的合理性)
1 /* n個隨機數,總和為sum,每個隨機數的范圍為[min,max]。 2 前n-1個用rand函數隨機產生,第n個數設為val=sum-(前n-1數之和)。 3 (1)若val屬於[min,max],則可以直接用; 4 (2)若val>=max,則用max。val-max的處理:在1~n-1中隨機出一個序號m來,將多出來的val-max補到這第m個數上,如果將其補為200仍然還有剩余,則繼續做這樣的操作,直到多余部分被分配完為止。 5 (3)若val<=min,則用min。min-val的處理:在1~n-1中隨機出一個序號m來,將多出來的min-val部分從這第m個數上扣除,如果將其削為min仍然沒有扣完,則繼續這個操作,直到配平為止。*/ 6 7 public class RandomGenerator 8 { 9 /// <summary> 10 /// 生成指定個數的限定金額范圍的隨機紅包,且總額為指定值 11 /// </summary> 12 /// <param name="totalValue">指定總額</param> 13 /// <param name="min">最小邊界</param> 14 /// <param name="max">最大邊界</param> 15 /// <param name="num">數量</param> 16 /// <returns>以列表的形式返回生成的數據</returns> 17 public List<double> RandomData(double totalValue, double min, double max, int num, out string message) 18 { 19 if (min > max) 20 { 21 message = "min > max,參數錯誤"; 22 } 23 24 List<double> list = new List<double>(); 25 26 //判斷參數合理性 27 if (min * num == totalValue) 28 { 29 for (int i = 0; i < num ; i++) 30 { 31 list.Add(min); 32 } 33 message = "fixedValue"; 34 return list; 35 } 36 if (min * num > totalValue) 37 { 38 message = "min * num > totalValue,參數不合理"; 39 return null; 40 } 41 if (max * num == totalValue) 42 { 43 for (int i = 0; i < num; i++) 44 { 45 list.Add(max); 46 } 47 message = "fixedValue"; 48 return list; 49 } 50 if (max * num < totalValue) 51 { 52 message = "max * num < totalValue,參數不合理"; 53 return null; 54 } 55 56 double sum = 0.0; 57 Random random = new Random(); 58 double diffValue = max - min; 59 60 double temp; 61 //前num-1個數據隨機生成 62 for (int i = 0; i < num-1; i++) 63 { 64 temp = Math.Round(random.NextDouble() * diffValue + min, 2); 65 sum += temp; 66 list.Add(temp); 67 } 68 //為了保證總額為指定值,須對最后一個數據的生成做處理 69 double gap = totalValue-sum; 70 if (gap >= min && gap <= max) 71 { 72 list.Add(gap); 73 message = "success"; 74 return list; 75 } 76 else if (gap > max) 77 {//剩余值大於max 78 list.Add(max); 79 gap = gap - max; 80 int index; 81 double value; 82 while (gap > 0) 83 { 84 index = random.Next(num - 1); //生成0到num-1之間的隨機整數(包括0,不包括num-1) 85 value = list[index]; 86 double margin = max - value; 87 if (margin>0) 88 { 89 if (gap >= margin) 90 { 91 list[index] = max; 92 gap = gap - margin; 93 } 94 else 95 { 96 list[index] = list[index] + gap; 97 message = "success"; 98 return list; 99 } 100 } 101 } 102 } 103 else //剩余值小於min 104 { 105 list.Add(min); 106 double need = min-gap; 107 int index; 108 double value; 109 double buffer; 110 while (need > 0) 111 { 112 index = random.Next(num - 1); //生成0到num-1之間的隨機整數(包括0,不包括num-1) 113 value = list[index]; 114 buffer = value - min; 115 if (buffer >= need) 116 { 117 list[index] = list[index] - need; 118 message = "success"; 119 return list; 120 } 121 else 122 { 123 list[index] = min; 124 need = need - buffer; 125 } 126 } 127 } 128 message = "success"; 129 return list; 130 } 131 132 }
試驗結果:




第二組:min=50,max=200,n=20000,sum=1200000(部分數據截圖如下)
總結:從試驗結果來看,這種算法生成的數據並不理想,明顯大量的數據落在了范圍的分界點上。因此不適用。
結果分析:當平均值遠大於最大最小值中位數(中位數代表隨機值圍繞上線抖動范圍)時,會導致隨機分配完之后剩余金額較多,而算法采用隨機選人進行累加,達到上限后繼續隨機人員,從而導致大部分人處在上限邊界;
反之,平均值小於中位數時,大部分人處於下限邊界。
算法嘗試改進:
嘗試改進一
這里對每個值先在范圍內隨機賦值,剩余值進行平均加到每個人上,保證原有值的隨機性;但是,加入剩余平均值為r_avg,這樣計算之后,每個人的金額范圍會變為[min+r_avg, max+r_avg]。
max+r_avg問題會導致某些人加r_avg之后大於最大值,可以嘗試把value(i)+r_avg>=max的人排除;
min+r_avg會導致min~min+r_avg之間無人數,嘗試計算min~min+r_avg之間應有人數min_n = (max-min)/n * r_avg = (max-min)/n * r_sum/n = (max-min)*r_sum/n*n,排除這些人。但是這樣又會導致[min+avg, min+avg+avg]之間斷層。這個問題可以通過隨機選n/2來變相解決,但是有點不合理,目前來看沒有好的解決方案。
嘗試改進二
1)這里對每個值先在范圍內隨機賦值;
2)遍歷每個值,在范圍[0, max-value(i)]內計算個隨機值;即random(i);
3)判斷剩余金額r_sum-random(i)的值是否變號。如原r_sum為5,隨機金額為7,5-7=-2,即變號;
4)如果變號,取value(i) = value(i) + r_sum,程序終止;
5)如果未變號,value(i) = value(i) + random(i)。繼續遍歷下個值重復2。
另外,如果剩余值為負,同樣道理,只是隨機數范圍是[0, value(i)-min],而且遍歷每個值要減去這個隨機數。
( 二)、方案二:
1 //每個紅包先分配min元,其余的再隨機分(隨機位置在符合金額范圍內隨機加錢,分完為止)。 2 public class RandomGeneratorNew 3 { 4 public List<double> RandomData(double totalValue, double min, double max, int num, out string message) 5 { 6 if (min > max) 7 { 8 message = "min > max,參數錯誤"; 9 } 10 11 List<double> list = new List<double>(); 12 13 //判斷參數合理性 14 if (min * num == totalValue) 15 { 16 for (int i = 0; i < num; i++) 17 { 18 list.Add(min); 19 } 20 message = "fixedValue"; 21 return list; 22 } 23 if (min * num > totalValue) 24 { 25 message = "min * num > totalValue,參數不合理"; 26 return null; 27 } 28 if (max * num == totalValue) 29 { 30 for (int i = 0; i < num; i++) 31 { 32 list.Add(max); 33 } 34 message = "fixedValue"; 35 return list; 36 } 37 if (max * num < totalValue) 38 { 39 message = "max * num < totalValue,參數不合理"; 40 return null; 41 } 42 43 double left; 44 Random random = new Random(); 45 double diffValue = max - min; 46 47 double tempAdd; 48 //每個紅包先分配min元 49 for (int i = 0; i < num; i++) 50 { 51 list.Add(min); 52 } 53 int index; 54 double value; 55 left=totalValue-min*num;//剩余未分配金額 56 while (Math.Round(left,2) > 0) 57 { 58 index = random.Next(num - 1); //生成0到num-1之間的隨機整數(包括0,不包括num-1) 59 value = list[index]; 60 double maxMargin = NumMIN(max, left,max-value); 61 if (Math.Round(maxMargin, 2) == 0) 62 break; 63 tempAdd = Math.Round(random.NextDouble() * maxMargin, 2); 64 list[index] = value + tempAdd; 65 left -= tempAdd; 66 } 67 message = "success"; 68 return list; 69 } 70 71 private double NumMIN(double p1, double p2, double p3) 72 { 73 double temp = p1 < p2 ? p1 : p2; 74 return temp < p3 ? temp : p3; 75 } 76 77 }
試驗結果:
min=1,max=200,n=30000,sum=100000。結果如下(部分數據截圖):
總結:從試驗結果來看,這種算法生成的數據並不理想,大部分數據都集中在了最小值上。因此這種算法不能接受。
結果分析:這里之所以出現這種情況,是因為在最小值比較小,中位數(100)遠遠大於平均值(3)的情況下,再進行剩余金額分配時,剛分配少量幾個位置余額就分配完了。
(三)、方案三:
隨機撒開,0.01撒開,再撒。即按照0.01隨機選擇位置進行累加,直至剩余金額為0。
1 //隨機撒開,0.01撒開,再撒 2 public class RandomTest 3 { 4 /// <summary> 5 /// 生成指定個數的限定金額范圍的隨機紅包,且總額為指定值 6 /// </summary> 7 /// <param name="totalValue">指定總額</param> 8 /// <param name="min">最小邊界</param> 9 /// <param name="max">最大邊界</param> 10 /// <param name="num">數量</param> 11 /// <returns>以列表的形式返回生成的數據</returns> 12 public List<decimal> RandomData(decimal totalValue, decimal min, decimal max, int num, out string message) 13 { 14 if (min > max) 15 { 16 message = "min > max,參數錯誤"; 17 } 18 19 List<decimal> list = new List<decimal>(); 20 21 //判斷參數合理性 22 if (min * num == totalValue) 23 { 24 for (int i = 0; i < num; i++) 25 { 26 list.Add(min); 27 } 28 message = "fixedValue"; 29 return list; 30 } 31 if (min * num > totalValue) 32 { 33 message = "min * num > totalValue,參數不合理"; 34 return null; 35 } 36 if (max * num == totalValue) 37 { 38 for (int i = 0; i < num; i++) 39 { 40 list.Add(max); 41 } 42 message = "fixedValue"; 43 return list; 44 } 45 if (max * num < totalValue) 46 { 47 message = "max * num < totalValue,參數不合理"; 48 return null; 49 } 50 Random random = new Random(); 51 decimal remainder = totalValue; 52 int index; 53 //每個紅包初始化賦值,先保證min 54 for (int i = 0; i < num; i++) 55 { 56 list.Add(min); 57 } 58 while (remainder!=0) 59 { 60 index = random.Next(num); //生成0到num之間的隨機整數(包括0,不包括num) 61 if (list[index] + (decimal)0.01 <= max) 62 { 63 list[index] += (decimal)0.01; 64 remainder -= (decimal)0.01; 65 } 66 } 67 message = "success"; 68 return list; 69 } 70 71 72 }
試驗結果:
min=1,max=200,n=30000,sum=100000。結果如下(部分數據截圖):
總結:從試驗結果來看,這種算法生成的數據並不理想,數據比較接近,沒有達到在范圍內隨機的目的。
結果分析:這里因為按照0.01最細粒度進行隨機撒開,當金額數量比較大時,隨機撒的次數比較多,那么從統計學上來說每個位置被選中的次數比較接近,所以會造成金額比較相近的結果。但是也不能按照粗粒度進行隨機撒,這樣會造成所有值都是粗粒度的倍數的情況出現。
(四)、方案四:(最終采用的方案)
1 public List<decimal> RandomData(decimal totalValue, decimal min, decimal max, int num, out string message) 2 { 3 decimal mu = totalValue / num; 4 List<decimal> data; 5 6 if (mu - min <= max - mu) 7 { 8 data = RandomDataLeft(totalValue, min, max, num, out message); 9 } 10 else 11 { 12 data = RandomDataRight(totalValue, min, max, num, out message); 13 } 14 return data; 15 } 16 public decimal AdjustData(decimal temp, decimal min, decimal max)//修正數據 17 { 18 if (temp < min) 19 { 20 temp = min; 21 } 22 if (temp > max) 23 { 24 temp = max; 25 } 26 return temp; 27 } 28 public List<decimal> RandomDataLeft(decimal totalValue, decimal min, decimal max, int num, out string message) 29 { //這個方法適用於max-mu>=mu-min的時候 30 List<decimal> list = new List<decimal>(); 31 32 if (max / (20 + min) >= 2) 33 return RandomDataLeftAdjust(totalValue, min, max, num, out message); 34 35 36 37 decimal maxMargin = 0; 38 //decimal mu = totalValue / num; 39 //decimal mu = Math.Round(totalValue / num, 2); 40 decimal mu = Math.Round(totalValue / num, 2); 41 Random random = new Random(); 42 decimal diffValue = max - min; 43 int count = num; 44 45 decimal factor = mu - min; 46 decimal temp; 47 48 //最多可以幾個數拼湊 49 int maxIndex; 50 decimal remainder = (max - min) % factor; 51 if (remainder == 0) 52 maxIndex = (int)((max - min) / factor); 53 else 54 maxIndex = (int)((max - min) / factor) + 1; 55 56 decimal a; 57 decimal b; 58 int index = 2; 59 60 61 while (count > 1) 62 { 63 64 if (count > maxIndex) 65 { 66 //正常流程 67 temp = Math.Round((decimal)(random.NextDouble()) * diffValue + min, 2); 68 } 69 else 70 { 71 temp = Math.Round((decimal)(random.NextDouble()) * (count * factor) + min, 2);//當count大於2時,范圍邊界 min,min+count*factor,最后一個區間:min+(count-1)*factor,min+count*factor;;;當count=2時也通用 72 } 73 temp = AdjustData(temp, min, max); 74 list.Add(temp); 75 a = min; 76 b = min + 2 * factor; 77 while (!(temp >= a && temp <= b)) 78 { 79 a = b; 80 b += factor; 81 if (b >= max) 82 b = max; 83 index++; 84 } 85 //此時index的值為多少(n),就表示需要多少個數,總和為mu*index 86 if (index == 2) 87 { 88 count -= 2; 89 //list.Add(mu * 2 - temp); 90 if (count == 0) 91 list.Add(totalValue - list.Sum()); 92 else 93 list.Add(AdjustData(Math.Round(mu * 2 - temp, 2),min,max)); 94 continue; 95 } 96 decimal partialSum = mu * index; 97 count -= index; 98 while (index != 2) 99 { 100 partialSum = partialSum - temp; 101 maxMargin = partialSum - (index - 2) * min; 102 temp = Math.Round((decimal)(random.NextDouble()) * (maxMargin - min) + min, 2); 103 temp = AdjustData(temp, min, max); 104 list.Add(temp); 105 index--; 106 } 107 partialSum -= temp; 108 if (count == 0) 109 { 110 decimal tempSum = list.Sum(); 111 list.Add(totalValue - list.Sum()); 112 } 113 else 114 list.Add(AdjustData(Math.Round(partialSum, 2),min,max)); 115 } 116 if (count == 1) 117 { 118 //list.Add(Math.Round(mu,2)); 119 decimal tempSum = list.Sum(); 120 list.Add(totalValue - list.Sum()); 121 } 122 123 //檢驗校正 124 125 message = "success"; 126 127 list = checkAndAdjust(list,min,max);//看最后一個數據是否符合要求,如果不符合需處理 128 129 //在返回數據之前再打亂一下順序 130 Random RND = new Random(DateTime.Now.Millisecond); 131 list = list.OrderBy(x => RND.Next()).ToList(); 132 return list; 133 } 134 135 public List<decimal> checkAndAdjust(List<decimal> list,decimal min, decimal max) 136 { 137 decimal lastNum = list[list.Count - 1]; 138 decimal diff; 139 Random random = new Random(); 140 if (lastNum < min) 141 { 142 list[list.Count - 1] = min; 143 diff = min - lastNum;//多算了diff,需從其他元素中減去 144 145 while(diff!=0) 146 { 147 int index = random.Next(list.Count - 1); 148 if (list[index] > min) 149 { 150 if (list[index] - min > diff) 151 { 152 list[index] -= diff; 153 diff = 0; 154 } 155 else if (list[index] - min < diff) 156 { 157 diff = diff - (list[index] - min);//還剩diff需從其他元素中減去 158 list[index] = min; 159 } 160 else { //= 161 list[index] = min; 162 diff = 0; 163 } 164 } 165 } 166 return list; 167 } 168 else if (lastNum > max) 169 { 170 list[list.Count - 1] = max; 171 diff = lastNum - max;//少算了diff,需加入其他元素中去 172 while (diff != 0) 173 { 174 int index = random.Next(list.Count - 1); 175 if (list[index] < max) 176 { 177 if (max - list[index] > diff) 178 { 179 list[index] += diff; 180 diff = 0; 181 } 182 else if (max - list[index] < diff) 183 { 184 list[index] = max; 185 diff = diff - (max - list[index]);//還剩diff需要加進其他元素中 186 } 187 else 188 { 189 list[index] = max; 190 diff = 0; 191 } 192 } 193 } 194 return list; 195 } 196 else //最后一個元素剛好也符合條件,則不需處理 197 { 198 return list; 199 } 200 } 201 202 public List<decimal> RandomDataRight(decimal totalValue, decimal min, decimal max, int num, out string message) 203 {//這個方法適用於max-mu<mu-min的時候 204 205 List<decimal> list = new List<decimal>(); 206 207 decimal minMargin = 0; 208 //decimal mu = totalValue / num; 209 //decimal mu = Math.Round(totalValue / num, 2); 210 decimal mu = Math.Round(totalValue / num, 2); 211 Random random = new Random(); 212 decimal diffValue = max - min; 213 int count = num; 214 215 decimal factor = max - mu; 216 decimal temp; 217 decimal lastNum; 218 decimal left; 219 220 //最多可以幾個數拼湊 221 int maxIndex; 222 decimal remainder = (max - min) % factor; 223 if (remainder == 0) 224 maxIndex = (int)((max - min) / factor); 225 else 226 maxIndex = (int)((max - min) / factor) + 1; 227 228 decimal a; 229 decimal b; 230 int index = 2; 231 232 233 while (count > 1) 234 { 235 236 if (count > maxIndex) 237 { 238 //正常流程 239 temp = Math.Round((decimal)(random.NextDouble()) * diffValue + min, 2); 240 } 241 else 242 { 243 temp = Math.Round((decimal)(random.NextDouble()) * (count * factor) + max - count * factor, 2);//范圍:(max-count*factor,max) 244 } 245 list.Add(temp); 246 a = max - 2 * factor; 247 b = max; 248 while (!(temp >= a && temp <= b)) 249 { 250 b = a; 251 a -= factor; 252 if (a < min) 253 a = min; 254 index++; 255 } 256 //此時index的值為多少(n),就表示需要多少個數,總和為mu*index 257 if (index == 2) 258 { 259 count -= 2; 260 if (count == 0) 261 { 262 lastNum = totalValue - list.Sum(); 263 if (lastNum <= max) 264 list.Add(lastNum); 265 else 266 { 267 list.Add(max); 268 left = lastNum - max; 269 int pos; 270 while (true) 271 { 272 pos = random.Next(num); 273 if (max - list[pos] >= left) 274 { 275 list[pos] += left; 276 break; 277 } 278 } 279 } 280 281 } 282 else 283 list.Add(Math.Round(mu * 2 - temp, 2)); 284 continue; 285 } 286 decimal partialSum = mu * index; 287 count -= index; 288 while (index != 2) 289 { 290 partialSum = partialSum - temp; 291 minMargin = partialSum - (index - 2) * max; 292 temp = Math.Round((decimal)(random.NextDouble()) * (max - minMargin) + minMargin, 2); 293 list.Add(temp); 294 index--; 295 } 296 partialSum -= temp; 297 if (count == 0) 298 { 299 lastNum = totalValue - list.Sum(); 300 if (lastNum <= max) 301 list.Add(lastNum); 302 else 303 { 304 list.Add(max); 305 left = lastNum - max; 306 int pos; 307 while (true) 308 { 309 pos = random.Next(num); 310 if (max - list[pos] >= left) 311 { 312 list[pos] += left; 313 break; 314 } 315 } 316 } 317 } 318 else 319 list.Add(Math.Round(partialSum, 2)); 320 } 321 if (count == 1) 322 { 323 lastNum = totalValue - list.Sum(); 324 if (lastNum <= max) 325 list.Add(lastNum); 326 else 327 { 328 list.Add(max); 329 left = lastNum - max; 330 int pos; 331 while (true) 332 { 333 pos = random.Next(num); 334 if (max - list[pos] >= left) 335 { 336 list[pos] += left; 337 break; 338 } 339 } 340 } 341 } 342 343 //檢驗校正 344 345 message = "success"; 346 list = checkAndAdjust(list, min, max);//看最后一個數據是否符合要求,如果不符合需處理 347 //在返回數據之前再打亂一下順序 348 Random RND = new Random(DateTime.Now.Millisecond); 349 list = list.OrderBy(x => RND.Next()).ToList(); 350 return list; 351 } 352 353 private List<decimal> RandomDataLeftAdjust(decimal totalValue, decimal min, decimal max, int num, out string message) 354 { 355 356 List<decimal> list = new List<decimal>(); 357 358 int ratio;//概率比例調整倍數 359 int maxReduce;//最大值縮小倍數 360 361 int tempMaxReduce = (int)(max % (20 + min)); 362 if (tempMaxReduce == 0) 363 maxReduce = (int)(max / (20 + min)); 364 else 365 { 366 maxReduce = (int)(max / (20 + min)) + 1; 367 if (maxReduce >= max / min) 368 maxReduce--; 369 } 370 371 int tempRatio = num / 5; 372 ratio = tempRatio > 200 ? 200 : tempRatio; 373 374 decimal maxMargin = 0; 375 //decimal mu = totalValue / num; 376 //decimal mu = Math.Round(totalValue / num, 2); 377 decimal mu = Math.Round(totalValue / num, 2); 378 Random random = new Random(); 379 decimal diffValue = max - min; 380 int count = num; 381 382 decimal factor = mu - min; 383 decimal temp; 384 385 //最多可以幾個數拼湊 386 int maxIndex; 387 decimal remainder = (max - min) % factor; 388 if (remainder == 0) 389 maxIndex = (int)((max - min) / factor); 390 else 391 maxIndex = (int)((max - min) / factor) + 1; 392 393 decimal a; 394 decimal b; 395 int index = 2; 396 397 int flag = 1; 398 int mode; 399 decimal modediffValue = max / maxReduce - min; //縮小多少倍,這個參數10可根據實際情況來調節 !!小心會不會出現max/10<min的情況??? 400 401 while (count > 1) 402 { 403 if (flag % ratio == 0) //這個比例的控制也可以根據實際情況來調節 404 mode = 1; 405 else 406 mode = 0; 407 flag++; 408 if (count > maxIndex) 409 { 410 //正常流程 411 412 if (mode == 1) 413 temp = Math.Round((decimal)(random.NextDouble()) * diffValue + min, 2); 414 else 415 temp = Math.Round((decimal)(random.NextDouble()) * modediffValue + min, 2); 416 } 417 else 418 { 419 if (mode == 1) 420 temp = Math.Round((decimal)(random.NextDouble()) * (count * factor) + min, 2);//當count大於2時,范圍邊界 min,min+count*factor,最后一個區間:min+(count-1)*factor,min+count*factor 421 else 422 { 423 decimal tempMargin = (count * factor) < modediffValue ? (count * factor) : modediffValue; 424 temp = Math.Round((decimal)(random.NextDouble()) * tempMargin + min, 2); 425 } 426 } 427 temp = AdjustData(temp, min, max); 428 list.Add(temp); 429 a = min; 430 b = min + 2 * factor; 431 while (!(temp >= a && temp <= b)) 432 { 433 a = b; 434 b += factor; 435 if (b >= max) 436 b = max; 437 index++; 438 } 439 //此時index的值為多少(n),就表示需要多少個數,總和為mu*index 440 if (index == 2) 441 { 442 count -= 2; 443 //list.Add(mu * 2 - temp); 444 if (count == 0) 445 list.Add(totalValue - list.Sum()); 446 else 447 list.Add(AdjustData(Math.Round(mu * 2 - temp, 2),min,max)); 448 continue; 449 } 450 decimal partialSum = mu * index; 451 count -= index; 452 while (index != 2) 453 { 454 partialSum = partialSum - temp; 455 maxMargin = partialSum - (index - 2) * min; 456 temp = Math.Round((decimal)(random.NextDouble()) * (maxMargin - min) + min, 2); 457 temp = AdjustData(temp, min, max); 458 list.Add(temp); 459 index--; 460 } 461 partialSum -= temp; 462 if (count == 0) 463 { 464 decimal tempSum = list.Sum(); 465 list.Add(totalValue - list.Sum()); 466 } 467 else 468 list.Add(AdjustData(Math.Round(partialSum, 2),min,max)); 469 } 470 if (count == 1) 471 { 472 //list.Add(Math.Round(mu,2)); 473 decimal tempSum = list.Sum(); 474 list.Add(totalValue - list.Sum()); 475 } 476 477 //檢驗校正 478 479 message = "success"; 480 //在返回數據之前再打亂一下順序 481 Random RND = new Random(DateTime.Now.Millisecond); 482 list = list.OrderBy(x => RND.Next()).ToList(); 483 return list; 484 }
二、符合正態分布的隨機紅包
1 /// <summary> 2 /// 生成符合正態分布的隨機數據 3 /// </summary> 4 /// <param name="r"></param> 5 /// <param name = "mu">Mean of the distribution</param> 6 /// <param name = "sigma">Standard deviation</param> 7 /// <returns></returns> 8 private decimal NextGaussian(Random r, decimal mu = 0, decimal sigma = 1) 9 { 10 var u1 = r.NextDouble(); 11 var u2 = r.NextDouble(); 12 var rand_std_normal = (decimal)(Math.Sqrt(-2.0 * Math.Log(u1)) * 13 Math.Sin(2.0 * Math.PI * u2)); 14 15 var rand_normal = mu + sigma * rand_std_normal; 16 17 return rand_normal; 18 } 19 public List<decimal> NorDist(decimal totalValue, decimal min, decimal max, int num, out string message) 20 { 21 try 22 { 23 decimal mu = (max + min) / 2; 24 decimal sigma = (max - mu) / 3; 25 decimal tempSum = 0; 26 27 var r = new Random(); 28 List<decimal> list = new List<decimal>(); 29 decimal randomData; 30 for (int i = 0; i < num - 1; i++) //先生成前num-1個數據 31 { 32 randomData = NextGaussian(r, mu, sigma); 33 for (; randomData < min || randomData > max; ) 34 randomData = NextGaussian(r, mu, sigma); 35 randomData = Math.Round(randomData, 2); 36 tempSum += randomData; 37 list.Add(randomData); 38 } 39 decimal diff = totalValue - tempSum; 40 if (diff >= min && diff <= max) 41 { 42 tempSum += diff; 43 list.Add(diff); 44 message = "success"; 45 return list; 46 } 47 else 48 { 49 decimal miniUnit = 0.1M; 50 randomData = NextGaussian(r, mu, sigma); 51 for (; randomData < min || randomData > max; ) 52 randomData = NextGaussian(r, mu, sigma); 53 randomData = Math.Round(randomData, 2); 54 tempSum += randomData; 55 list.Add(randomData); 56 diff = totalValue - tempSum; 57 int k = -1; 58 decimal n; 59 60 if (diff > 0) 61 { //即預定資金沒用完 62 for (n = diff; n >= miniUnit; n = n - miniUnit) 63 { 64 k = (k + 1) % num; 65 while (list[k] > max - miniUnit) 66 { 67 k = (k + 1) % num; 68 } 69 list[k] += miniUnit; 70 } 71 if (n != 0) 72 { 73 while (list[k] + n > max) 74 { 75 if (k > 0) 76 k = k - 1; 77 else 78 { 79 message = "正態分布分配失敗,請重試"; 80 return null; //分配失敗 81 } 82 } 83 list[k] += n; 84 } 85 } 86 else //即diff<0,不可能出現=0的情況 ,此時分配資金超出預定,需要回收 87 { 88 diff = -diff; 89 for (n = diff; n >= miniUnit; n = n - miniUnit) 90 { 91 k = (k + 1) % num; 92 while (list[k] < min + miniUnit) 93 { 94 k = (k + 1) % num; 95 } 96 list[k] -= miniUnit; 97 } 98 if (n != 0) 99 { 100 while (list[k] - n < min) 101 { 102 if (k > 0) 103 k = k - 1; 104 else 105 { 106 message = "正態分布分配失敗,請重試"; 107 return null; //分配失敗 108 } 109 } 110 list[k] -= n; 111 } 112 } 113 } 114 115 message = "success"; 116 return list; 117 } 118 catch (Exception ex) 119 { 120 Logger.Error("HRPortal -> NorDist方法異常", ex); 121 message = "分配金額失敗,請重試"; 122 return null; 123 } 124 }
三、網上找到的例子:(生成隨機紅包一)
(1)https://www.zhihu.com/question/22625187
(2)
1 /** 2 * 計算隨機值 3 * @input: min 最小金額(默認為1, 0.01元) 4 * max 最大金額(默認為20000, 200元) 5 * total 剩余總金額 6 * num 剩余總人數 7 * @return: 本次隨機金額 8 */ 9 LONG HbReceive::calcRandomValue(LONG min, LONG max, LONG total, LONG num) 10 throw (CException) 11 { 12 if(num == 1) 13 { 14 return total; 15 } 16 17 // 更新隨機種子 18 srand(time(NULL)); 19 20 // 確定本次隨機范圍 21 LONG low = (total - (num-1)*max) < min ? min : total - (num-1)*max; 22 23 LONG high = (total - (num-1)*min) > max ? max : (total - (num-1)*min); 24 25 LONG ave = total / num > 1 ? total / num : 1; 26 27 // 調整上限 28 if(high > 2 * ave) high = 2 * ave; 29 30 // 生成隨機值 31 LONG ram = random() % high; 32 33 // 防止溢出 34 if(ram < low) ram = low; 35 36 if(ram > high) ram = high; 37 38 return ram; 39 }
輸出到文件中代碼:
1 public void outputToFile(List<decimal> list) 2 { 3 FileStream fs = new FileStream("D:\\RandomTest.txt", FileMode.Append); 4 StreamWriter sw = new StreamWriter(fs, Encoding.Default); 5 foreach (var item in list) 6 { 7 //sw.WriteLine(item); 8 sw.Write(item); sw.Write('\t'); 9 } 10 sw.Close(); 11 fs.Close(); 12 }

