连续加权随机分布,偏向一端


28

我目前正在为我们的游戏的粒子系统做出贡献,并开发了一些发射器形状。

我沿直线或矩形区域的均匀随机分布效果很好-没问题。

但是现在,我希望在这种分布中具有一维梯度。例如,这意味着较低的值比较高的值更常见。

我不知道什么数学术语可以解决这个问题,因此我的搜索技能对这个问题毫无用处。我需要一些计算简单的东西,因为粒子系统需要高效。



没有人会提到微积分吗?
亚历克·蒂尔

Answers:


42

看一下这张照片:

曲线贴图

它显示了将(随机)值映射到曲线的过程。假设您生成一个范围从0到1的均匀分布的随机值X。通过将该值映射到曲线上-或者换句话说,使用f(X)而不是X-您可以按照自己喜欢的任何方式倾斜分布。

在这张照片中,第一个曲线使更高的值更有可能出现;第二个使更低的值更有可能;第三个使价值集群在中间。曲线的确切公式并不十分重要,可以根据需要选择。

例如,第一条曲线看起来有点像平方根,第二条曲线看起来像平方。第三个有点像多维数据集,只能翻译。如果您认为平方根太慢,则第一条曲线也看起来像f(X)= 1-(1-X)^ 2-平方的倒数。或夸张:f(X)= 2X /(1 + X)。

如第四条曲线所示,您可以简单地使用预先计算的查找表。看起来很丑陋,但是对于粒子系统可能已经足够了。

这种通用技术非常简单而且功能强大。无论您需要什么分布,只要想象一下曲线映射,就可以立即设计一个公式。或者,如果您的引擎具有编辑器,则只需为曲线创建可视化编辑器即可!


非常感谢您的详尽而易懂的解释。其他所有帖子也都非常有帮助,但是我确实可以最轻松,最快地了解您的帖子。它非常适合我理解事物的方式。您正在解释的方面正是我正在寻找(或徘徊)的内容!它使我将来可以在很多情况下使用此功能。所以再次谢谢!顺便说一句,我玩了一些你的曲线,它就像魅力。
didito

5
仅供参考:这些被称为分位数函数:en.wikipedia.org/wiki/Quantile_function
Neil G

8

更长的解释:

如果您具有所需的概率分布,例如要求的梯度@didito,则可以将其描述为一个函数。假设您想要一个三角分布,其中0处的概率为0.0,并且想要选择一个从0到1的随机数。我们可以将其写为y = x。

下一步是计算此函数的积分。在这种情况下,它的X=1个X2。从0到1评估为½。这是有道理的-它是一个底数为1且高度为1的三角形,因此其面积为½。

然后,您从0到区域(在我们的示例中为½)均匀地选择一个随机点。我们称这个z。(我们从累积分布中统一选择。)

下一步是倒退,找出x的值(我们称为x̂)对应于z的面积。我们正在寻找X=1个X2,从0到x̂求值,等于z。当你解决1个X̂2=ž,你会得到X̂=2ž

在此示例中,您从0到½中选择z,然后所需的随机数是2ž。简化后,可以写成[R一种ñd01个 -正是电子商务推荐。


谢谢您的宝贵意见。我一直喜欢听到熟练的人如何解决问题。但老实说,我仍然需要把
头缠起来

这太棒了。我sqrt(random())一生都在努力,但我凭经验去尝试。尝试将随机数绑定到曲线上,它确实起作用。现在,我对数学有了更多的了解,知道为什么它很有价值!
古斯塔沃·麦克尼尔

5

通过使用指数系统,您可能会很接近所需的内容。

使x基于1-(rnd ^ value)之类的值(假设rnd在0到1之间),您将根据自己的使用情况从左到右倾斜一些不同的行为。较高的价值将使您的分布更偏斜

您可以使用在线绘图工具来了解一些不同的方程式,然后再放入其中,然后粗略地了解其行为,也可以直接在粒子系统中摆弄这些方程式,这取决于您的口味。

编辑

对于类似粒子系统的每个粒子的CPU时间非常重要的事情,直接使用Math.Pow(或等效语言)可能会导致性能下降。如果需要更高的性能,并且在运行时未更改值,请考虑切换到等效函数,例如x * x而不是x ^ 2。

(分数指数可能更多,但是数学背景比我强的人可能会想出一种创建近似函数的好方法)


1
无需使用制图程序,您只需绘制Beta分布即可,因为这是特例。对于给定value,这是Beta(value,1)。
Neil G

谢谢。我试着画一些图,我认为它可以带我到想要的地方。
didito

@Neil G感谢您提供带有“ beta分布”的提示-听起来很有趣而且很有用...我将对该主题进行一些研究
didito 2011年

3

您正在寻找的术语是Weighted Random Numbers,我见过的大多数算法都使用trig函数,但是我想我想出了一种有效的方法:

创建一个表/数组/列表(无论如何),其中包含随机函数的乘数。手动或以编程方式填写...

randMulti= {.1,.1,.1,.1,.1,.1,.2,.2,.3,.3,.9,1,1,1,} 

...然后乘以random随机选择的randMulti,最后乘以分布的最大值...

weightedRandom = math.random()*randMulti[Math.random(randMulti.length)]*maxValue

我确实相信这将比使用sqrt或其他计算复杂的函数快得多,并且将允许使用更多自定义分组模式。


2
如果您可以牺牲内存,则包含100个预先计算的值的表将更快(并且稍微更准确)。我怀疑用户能否区分完整版本和预计算版本。
丹尼尔·布雷泽克

@Daniel会更快,但是有100个随机值,很容易看到重复的模式。
AttackingHobo

仅仅因为似乎存在重复模式并不意味着它不是随机的。随机性的本质是它的不可预测性,从字面上讲,它意味着尽可能多的人无法预测不会有一种模式,也不能预测可能有一种模式(至少在短时间内)。您必须进行一些测试,但是如果您确实发现了使用不同种子进行多次测试的模式,那么可能需要检查生成伪随机数的算法。
兰道夫·理查森

@AttackingHobo thx的技巧。我喜欢使用LUT。公式很容易理解 我以前没有这样想过。我还没有看到树木的树木... :)我也认为应该避免重复图案,但是在这种情况下可能不会被识别。尽管如此,预先计算所有值仍会损害视觉体验。无论如何,谢谢您提醒我,这是考虑随机性的一个因素……
didito 2011年

也感谢您提出了加权“随机数”一词!
didito

2

我认为您要求的是使用平方根函数实现的分布。

[position] = sqrt(rand(0, 1))

这将在[0, 1]一个位置的概率等于该位置的概率的单维度字段中给出分布,即“三角分布”。

备用无平方根生成:

[position] = 1-abs(rand(0, 1)-rand(0, 1))

最佳实现中的平方根只是几个没有分支的乘法和求和命令。(请参阅:http : //en.wikipedia.org/wiki/Fast_inverse_square_root)。这两个功能中哪个更快,取决于平台和随机生成器。例如,在x86平台上,随机生成器中仅需几个不可预测的分支即可使第二种方法变慢。


位置的概率将不等于位置(从数学上讲是不可能的-简单地说,函数的域和范围包括0.50和0.51),也不是三角形分布。(en.wikipedia.org/wiki/Triangular_distribution

1
尽管sqrt提供了一些有趣的模式,但粒子系统通常每个粒子都需要占用非常多的CPU光,因此我建议尽可能避免平方根(计算速度较慢)。有时您可以只对它们进行预先计算就可以逃脱,但是随着时间的流逝,它可以使您的粒子具有明显的模式。
鲁宁

1
@Joe Wreschnig,您是否亲自阅读了维基百科的文章,将a = 0,b = 1,c = 1填充到了生成公式中,您就在我的帖子中得到了该公式。
aaaaaaaaaaaaaa

3
@Lunin,当答案中有指数时,为什么还要抱怨平方根?
aaaaaaaaaaaaaa

1
@Lunin:性能理论是一个非常被忽略的领域,很多人认为他们知道30年前ALU昂贵而缓慢的正确地方。即使您刚刚发现它是一个相当慢的算术函数的指数函数,也很少会成为非常重要的性能缺陷。分支(使用if语句)和缓存未命中(读取当前不在缓存中的数据)通常是性能最高的原因。
aaaaaaaaaaaaaa

1

只需使用Beta版本:

  • Beta(1,1)是平坦的
  • Beta(1,2)是线性渐变
  • Beta(1,3)是平方的

等等

两个形状参数不必为整数。


谢谢您的帮助。如上所述,贝塔分布听起来很有趣。但是我还不能理解维基百科页面的内容。或公式/代码。好吧,我现在也没有时间进一步调查:si看到boost具有用于beta发行版的代码,但这太过分了。好吧,我想我需要先通过它,然后编写自己的简化版本。
didito

1
@didito:并不难。您只需将替换uniform_generator()为即可gsl_ran_beta(rng, a, b)。看到这里:gnu.org/software/gsl/manual/html_node/…–
Neil G

提示。我不使用GSL(实际上以前没有听说过),但是通话很好。我将检查源!
didito

@didito:在这种情况下,我会采用Lunin的解决方案。祝好运。
尼尔G

0

甚至更简单,根据随机生成器的速度,您可以生成两个值并将它们平均。

或者,甚至更简单,其中X是rng的结果,首先double y = double(1/x);x = y*[maximum return value of rng];。这会将数字加权成较低的数字。

生成并平均更多的值,以增加使值更接近中心的可能性。

当然,这仅适用于标准钟形曲线分布或其“折叠”版本*,但使用快速生成器,它可能比使用sqrt等各种数学函数更快,更简单。

您可以找到关于骰子钟形曲线的各种研究。实际上,Anydice.com是一个很好的网站,可以为掷骰子的各种方法生成图形。尽管您使用的是RNG,但前提和结果是相同的。因此,这是在编码之前查看分布的好地方。

*此外,您可以通过取一条轴并减去平均结果,然后再加上该轴,来沿轴“折叠”结果分布。例如,您希望较低的值更常见,例如,您希望最小值为15,最大值为35,范围为20。因此,您将两个范围为20(两倍于您想要的范围),这将产生一个以20为中心的钟形曲线(我们在末尾减去5,将范围从20变为40,从15变为35)。取生成的数字X和Y。

最终号码,

z =(x+y)/2;// average them
If (z<20){z = (20-z)+20;}// fold if below axis
return z-5;// return value adjusted to desired range

如果您的最小值是零,甚至更好,请改为这样做,

z= (x+y)/2;
If (z<20){z = 20-z;}
else {z = z - 20;}
return z;
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.