请问下,比较简单的实现 0.5 到 2 之间的随机数的方法

2020-11-13 14:54:37 +08:00
 ukipoi

要求就是 扩大一倍或者缩小一倍,两边的概率相同。

这个可以用 Math.radom(),仅以数学的方式,一行就完成吗?

我好像只能先随机出是扩大还是缩小,然后在分别写扩大 /缩小的倍率。

大大们可以给个其他的思路么?

7936 次点击
所在节点    程序员
103 条回复
idlerlestat
2020-11-13 17:43:53 +08:00
这……不就是 2^randint([-1,1])吗,randint 表示从一个数组里随机取一个数
wty
2020-11-13 17:46:38 +08:00
扩大和缩小比例本来就不均匀,感觉应该在对数上随机然后转换过来
cigarzh
2020-11-13 17:49:47 +08:00
先考虑精度+1

这个不理清楚后面没法做
xiaopang132
2020-11-13 17:54:25 +08:00
math.ramdom()*1.5 + 0.5
0o0o0o0
2020-11-13 17:54:54 +08:00
有个问题,“1/N 倍”概率如果要均匀分布,那肯定不是 if else 就能解决的
reus
2020-11-13 17:56:57 +08:00
@ukipoi 你才明白啊?我给你的答案就是两条直线推出来的公式啊。0-0.5 是缩小,0.5 到 1 是放大,概率一样,再映射到 0.5-1 和 1-2,答案不就出来了
设随机出来的是 x,要用的乘数是 y
那就是
Y =x + 0.5

Y= 2x
laqow
2020-11-13 17:57:54 +08:00
没看懂,感觉应该从概率分布和概率分布的计算方面找答案。random 没记错就是 uniform 分布,根据自己需要把这个分布转换成其它分布就完了。
CRVV
2020-11-13 17:59:33 +08:00
如果只考虑数学问题(不考虑什么浮点数运算的事情),也不考虑边界([] 和 () 的差别),这个问题是这样的

已有一个 0-1 之间均匀分布的随机数 x,在上面加一个变换 f,变成 0.5-2 之间分布的随机数 y,要求 0.5-1 的概率和 1-2 的概率相等。问这个变换是什么。

先假定 f 在 0.5-2 之间是单调连续函数(不单调的 f 当然也可以有,先不考虑了)

那么,f(0.5) = 1 且 0.5 <= f(x) <= 2 的 f 都符合要求,比如 f(x) = x + 0.5

如果再增加一个条件,y 在 0.5 - 2 的整个区间内的概率密度都不为 0
那么只要 f(0) = 0.5, f(0.5) = 1, f(1) = 2,f 就满足要求,你随便假设比如 f(x) = ax^2 + bx + c 然后解 a b c 就好了。
如果假设 f(x) = 2^(ax+b) ,就得到 lsylsy2 给出的指数函数。
类似的还有很多符合条件的函数。

如果再增加一个条件,0.5-1 和 1-2 之间的概率密度分别都是常数,那么两边都是直线。
给定 f(0) = 0.5, f(0.5) = 1, f(1) = 2,结果是唯一的,就是那个分段函数。
zhyl
2020-11-13 18:03:32 +08:00
分成两步:
1. 一颗石子落在数轴(整个数轴 0.5 ~ 2 )上,落在 0.5 ~ 1 范围的概率 = 1 ~ 2 范围的概率
2. 在落入的范围内取任意随机数,其概率都是相同的

计算步骤:
0. p = Math.random()
1. p <= 2/3 则 (重置随机数种子后) Math.random()*0.5 + 0.5
2. p > 2/3 则 (重置随机数种子后) Math.random()+1
cmdOptionKana
2020-11-13 18:27:44 +08:00
随机数有两种:一种是 0-1 之间取随机数,有无限个;另一种是在有限的数量中(比如 5 号小球至 20 号小球,共 16 个小球中)随机选一个。

区分这两种不同的方式来取随机数,就比较清晰了。
cmdOptionKana
2020-11-13 18:38:15 +08:00
因此,如果楼主说的是 0.5 - 2 之间的 *无限个* 数字中取随机数,那么,这个问题本身就是错的。

不存在这样的随机数,或者说这样设定范围必然会影响随机性。

从无限个数字中取随机数,只能是在 0-1 之间取,或者 1-2 这样可以无损转换成 0-1 的范围中取。比如 1-3 就不行,2-4 就可以。
cmdOptionKana
2020-11-13 18:39:21 +08:00
说错了,2-4 不行,2-3 可以,3-4 可以。
xymn
2020-11-13 18:42:23 +08:00
var rand = Math.random()
if(rand<0.25){
return r*8
}else{
return r*2
}
lancelock
2020-11-13 19:19:42 +08:00
随机范围 0-2,结果大于 1 直接乘,小于 1 的话先加 1 在反转作为分母,分子为 1,这个分数作为乘数
wchyqqgmail
2020-11-13 19:20:34 +08:00
random(1,4)/2
vgbhne
2020-11-13 20:30:25 +08:00
计算机浮点数虽然可能精度上有差距,但是落在(-1,1 )以零为原点的个数是一样的。具体生成的数经过计算或许是错的,但是不影响两边的概率。具体和底层设计也相关。
lance6716
2020-11-13 20:47:47 +08:00
充分证明程序员的数学基础有多差🤣
yanqiyu
2020-11-13 21:47:25 +08:00
扩大和缩小概率一样?你可能希望无论是扩大还是缩小概率分布都均匀(生成一个线性变换),抑或是一边均匀另一边按照幂函数映射(你原先的做法就是 best practice ),或者两边都不一定均匀但是要满足幂函数变换下的不变( exp(2, rand()))。

更一般的情况更为复杂(比如你需要指定某一侧具有复杂的概率密度函数形式)那就需要先计算出 pdf/cdf 做专门的生成器了( Inverse Transform Method )
cnt2ex
2020-11-13 23:57:04 +08:00
(2 * Math.random()) % 1.5 + 0.5
cnt2ex
2020-11-14 00:04:51 +08:00
```
import random

run = 1000000

first = 0
second = 0

for i in range(run):
rnd = (2 * random.random()) % 1.5 + 0.5
if rnd >= 0.5 and rnd < 1.:
first += 1
if rnd >= 1. and rnd < 2.:
second += 1

print(first / run, second / run, first + second == run)
```
试着跑了一下,0.5 到 1 和 1 到 2 之间的概率差不多都是 0.5

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/724860

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX