我正在编写一些代码来使用随机数来创建钟形曲线。
基本方法如下:
创建一个2001整数数组。
对于一些重复次数,请执行以下操作:
• Start with a value of 1000 (the center-value)
• Loop 1000 times
• Generate a random number 0 or 1. If the random number is zero, subtract 1 from the value. If it's 1, add 1 to the value.
• Increment the count in my array at the resulting index value.
所以1000次,我们从1000的起始值中随机地加1或减1。平均来说,我们将加1并且经常减去1,因此结果应该以1000为中心。值更大或者少于1000应少,少用。索引0或索引1处的值将需要"抛硬币"连续1000次使用相同的结果... 非常不太可能发生的事件仍然存在。
这是我提出的代码,用C语言编写,带有一个瘦的Objective C包装器:
#import "BellCurveUtils.h"
@implementation BellCurveUtils
#define KNumberOfEntries 1000
#define KPinCount 1000
#define KSlotCount (KPinCount*2+1)
static int bellCurveData[KSlotCount];
+(void) createBellCurveData;
{
NSLog(@"Entering %s", __PRETTY_FUNCTION__);
NSTimeInterval start = [NSDate timeIntervalSinceReferenceDate];
int entry;
int i;
int random_index;
//First zero out the data
for (i = 0; i< KSlotCount; i++)
bellCurveData[i] = 0;
//Generate KNumberOfEntries entries in the array
for (entry =0; entry<KNumberOfEntries; entry++)
{
//Start with a value of 1000 (center value)
int value = 1000;
//For each entry, add +/- 1 to the value 1000 times.
for (random_index = 0; random_index<KPinCount; random_index++)
{
int random_value = arc4random_uniform(2) ? -1: 1;
value += random_value;
}
bellCurveData[value] += 1;
}
NSTimeInterval elapsed = [NSDate timeIntervalSinceReferenceDate] - start;
NSLog(@"Elapsed time = %.2f", elapsed);
int startWithData=0;
int endWithData=KSlotCount-1;
for (i = 0; i< KSlotCount; i++)
{
if (bellCurveData[i] >0)
{
startWithData = i;
break;
}
}
for (i = KSlotCount-1; i>=0 ; i--)
{
if (bellCurveData[i] >0)
{
endWithData = i;
break;
}
}
for (i = startWithData; i <= endWithData; i++)
printf("value[%d] = %d\n", i, bellCurveData[i]);
}
@end
代码确实生成钟形曲线。但是,具有奇数索引的数组条目全部为零。
以下是一些示例输出:
value[990] = 23
value[991] = 0
value[992] = 22
value[993] = 0
value[994] = 20
value[995] = 0
value[996] = 25
value[997] = 0
value[998] = 37
value[999] = 0
value[1000] = 23
value[1001] = 0
value[1002] = 26
value[1003] = 0
value[1004] = 20
value[1005] = 0
value[1006] = 28
value[1007] = 0
value[1008] = 23
value[1009] = 0
value[1010] = 26
我逐行检查了这段代码,并且不明白为什么会这样。当我在调试器中逐步执行它时,我得到的值是单步反弹,从1000开始,下降到999,递增到1001,各种值甚至是奇数。但是,经过1000次迭代后,value
的结果始终。我在这里缺少什么?!?
我意识到这不是一个典型的SO开发问题,但我很难过。我看不出我做错了什么。有人可以解释这些结果吗?
答案 0 :(得分:3)
//For each entry, add +/- 1 to the value 1000 times.
for (random_index = 0; random_index<KPinCount; random_index++)
{
int random_value = arc4random_uniform(2) ? -1: 1;
value += random_value;
}
对于此循环的任何两次迭代,有三种可能的结果:
因此,如果循环运行偶数次(即KPinCount是偶数),则“值”的奇偶校验将永远不会改变。由于它以偶数(1000)开头,因此以偶数结束。
编辑:如果你想解决问题但是保持相同的基本方法,那么不是以value = 1000开始并运行1000次迭代,你可以在其中添加或减去一个,也许你可以以value = 0开始并运行2000次迭代,在其中添加一个或零。我已将此作为对上述讨论的评论发布,但由于我刚刚注册,因此无法发表评论。
答案 1 :(得分:1)
即时问题出在
for (random_index = 0; random_index < KPinCount; random_index++)
{
int random_value = arc4random_uniform(2) ? -1: 1;
value += random_value;
}
由于KPinCount
定义为1000(偶数),因此在循环结束时,value
将更改为2的倍数。
也许尝试使用KPinCount
在999和1000之间变化???
答案 2 :(得分:0)
好的,我已经对这个项目得到了一些非常有用的反馈。
总结:
如果您总是在一个值中加或减一个值,并且执行两次,则可能性为:
因此,在这种情况下,值总是会改变0或2,因此结果始终是偶数。
同样,如果您始终应用奇数个+ 1 / -1值更改,则结果值将始终为奇数。
提出了几种解决方案。
选项1 :(我在测试中使用的更改)是在计算每个值之前,随机决定循环999或1000次。这样,结果将是偶数的一半时间,另一半时间值将是奇数。
这导致图表的扩展将无限小,因为可能的值范围的一半时间将减少+/- 1。
选项2是生成3个随机值,并根据结果为该值添加+1,0或-1。
@rhashimoto在对其中一个答案的评论中建议的选项3是生成4个随机值,并根据结果为该值添加+1,0,0或-1。
我怀疑选项2和3会导致曲线的扩散范围变窄,因为每次迭代时可能的随机值的1/3或1/4,该值不会改变,因此值的平均值将是小。
我使用不同的设置进行了多次测试,并证实了我的怀疑。
以下是不同方法的图表。所有样本图都是1,000,000个点的图,图表被限制在800到1200之间,因为在实践中从不存在超出该范围的值。图表上的绿条位于中心点,+ / - 50步
首先,选项1,随机应用999或1000 +/- 1更改为起始值:
选项2,1000次迭代应用3个随机可能的变化,-1,0或+1:
选项3,1000次迭代应用4个随机可能的变化,-1,0,0或+1,如rhashimoto在对pmg的回答的评论中所建议的那样:
在Photoshop中将所有图形叠加在一起:
我使用更多的点(1亿而不是1百万)创建了图形,图形更平滑,更少“紧张”#34;但曲线的形状适用于所有实际目的相同。对一百万次迭代图的结果应用适度的滚动平均值无疑会产生非常平滑的曲线。