我试图获取一个货币价值(使用decimal
)并将其分解为分布在14个不同标签中的随机部分,这些标签加起来是原始值。
示例:值50.00
(不是确切的值,而是像这样的随机值,总计达到总数)
问题在于我无法弄清楚以下内容:
我正在使用的代码:
private void generatewins(Decimal amount)
{
Decimal initialValue = amount;
Decimal currentRemainder = amount;
var values = new List<int>();
Label[] labels = { win1, win5, win10, win9, win6, win2, win3, win7, win8, win11, win13, win12, win4 };
Random rnd = new Random();
Decimal remainingPortion = initialValue;
for (int i = 0; i < 13; i++)
{
Decimal val = currentRemainder - rnd.Next(14 - i);
currentRemainder -= val;
labels[i].Text = Convert.ToString(val) + "";
win14.Text = currentRemainder.ToString();
}
}
为了澄清一些事情,我使用标签的原因是我必须将这些标签放在表单上的特定位置,以便它们随表单大小和表单上的另一个对象而变化。我认为使用标签会更容易。此外,第14号不属于其余部分;它被设置为从初始值中取出剩余的,因为当我将它添加到随机分割值时,它总是会变为0而其他13个值将不会总和为初始值。
答案 0 :(得分:1)
好的,从问题2开始)他们是整数的原因是因为你的随机结果将是一个整数。使用rnd.NextDouble()代替,这会得到0到1之间的随机十进制数。
这可能听起来像是一个糟糕的范围,但它有利于解决问题1)结果开始大而后变小。这显然是因为随着循环的进行,您提供的随机范围会发生变化和缩小。我会做的只是循环通过14次(或者它是什么)并在0和1之间得到14个随机数。然后!将所有数字相加,将该总和除以总值(在您的情况下为50.00),然后再次检查并将所有数字乘以该结果。这将使数字加起来总数,并使所有数字都有相同的机会成为范围内的任何数据
decimal Total = 50.00;
decimal randTotal = 0;
decimal []values = new decimal[14];
for(int i = 0; i<14; i++)
{
values[i] = rnd.NextDouble();
randTotal += values[i]
}
decimal co = Total / randTotal;
for (int i = 0; i < 14; i++)
values[i] *= co;
值将是一个随机十进制数组,加起来为总计。
然后如果你想整理四舍五入(到最近的分) 我会做的是以下几点:
decimal leftOver = 0;
for(int i = 0; i<14; i++)
{
decimal centFraction = values[i] - Math.floor(values[i] * 100) / 100; //floor rounds a number down to the nearest whole number
values[i]-=centFraction;
leftOver+=centFraction;
}
//then just add the left over cents (which should be in whole cents!) to one of them
values[0]+=leftOver;
这可能不是最好的方法,因为从技术上来说,现在没有均匀分布,但可能会这样做?
P.S。问题3是由于您只是根据与总数无关的范围得到14个随机数这一事实。如果您的总金额为2美元,您可以清楚地看到您第一次拨打rnd.Next(14-i)(获得0到14之间的随机数)可能很容易导致数字大于2。
答案 1 :(得分:0)
我认为你需要一个类似
的循环decimal Total = 50.00M;
for ( i = 0; i <= 14; i++)
{
Random random = new Random();
decimal newDec = Math.Round((random.NextDouble(0 , Total) / 100),3));
//do something to log newDec
Total -= newDec;
}
答案 2 :(得分:0)
Random类返回整数。如果你想要十进制数,你可以除以100。
另请注意,Next的参数是随机数的大小。您应该将其限制为所需数量的大小。这就是你得到负数的原因 - 如果返回的随机数大于你当前的余数,(只要(14-i)最终大于当前余数就会发生这种情况,那么这个值就会出现负值。
随着您的第一个数字变大,请考虑第一次迭代的可能结果。随机数介于0到14之间,因此val结果必须始终在比原始数字小14的范围内。你真正想要的是一个偏态分布,其中第一个val可以是从零到原始值的任何地方,但平均值在某处(CurrentRemainder /(14-i))。这将提供更多随机值。我需要更多的数学专家才能知道确保正确随机数的最佳分布,但是如果每次迭代都保证在零到当前余数的范围内,那么至少你不会超过总数。一个简单的解决方案是将值限制在0到平均值的两倍之间,就像这样......
Decimal currentRemainder = initialValue;
for (int i = 0; i < 13; i++)
{
Decimal avg = (currentRemainder/(14-i));
Decimal val = currentRemainder - (rnd.Next(avg*2*100)/100);
currentRemainder -= val;
labels[i].Text = Convert.ToString(val) + "";
win14.Text = currentRemainder.ToString();
}
labels[13] = Convert.ToString(currentRemainder);
那应该非常接近。获得完全完美的随机分布将需要更多的数学来调整每个值,这有点超出我的范围。