调整生成随机强度值的算法

3

几天前,你帮助我找到了一个在线游戏中生成随机实力值的算法(特别感谢John Rasch)

function getRandomStrength($quality) {
    $rand = mt_rand()/mt_getrandmax();
    $value = round(pow(M_E, ($rand - 1.033) / -0.45), 1);
    return $value;
}

这个函数生成1.1到9.9之间的值。现在我想调整这个函数,使它给我同样概率的值,但在另一个区间内,例如1.5到8.0。如果您可以通过附加参数实现这一点,那将非常完美。

如果您能帮助我,那就太好了。提前感谢您!

3个回答

5

原始代码中的1.033和-0.45是提供比例1.1-9.9的神奇数字。如果您将1.1和9.9作为$low$high参数传入以下代码,则应该获得相同的结果。

function getRandomStrength($low, $high) {
    // TODO: validate the input
    $ln_low = log( $low, M_E );
    $ln_high = log( $high, M_E );
    $scale = $ln_high - $ln_low;

    $rand = ( mt_rand() / mt_getrandmax() ) * $scale + $ln_low;
    $value = round( pow( M_E, $rand), 1 );
    return $value;
}

你应该能够传入任何范围的 $low$high 并获得该范围内的对数分布。 (我会把范围有效性检查留给你,但是 0 < $low < $high 应该是正确的。)
这是通过反向计算必要的线性比例尺来生成所提供范围内的对数比例尺实现的。例如,如果我想让我的对数刻度为 1.1 - 9.9,我会取这些值的自然对数,从而得到 0.0953 - 2.2925。然后我在这个线性范围内生成一个随机数,并将其幂次方转换回对数范围。

谢谢,这几乎就是Jacob B所做的,不是吗?我用50000次运行测试了两种算法,Jacob B的算法稍微快一些(0.563871860504 vs 0.468094348907)。 - caw
@marco - 如果我是你,我肯定会使用这个答案,它不仅更干净,更易读,更通用,更易懂,而且更易于维护。这一点的价值远远超过在50000次运行中节省0.1秒的时间。如果你非常关注性能,你可能需要考虑切换平台 :) - John Rasch
好的,如果你这么说,那一定是真的! :) 毕竟,你是我的算法的“发明者”,所以你一定知道。 ;) 我已经改变了最佳答案标记。 - caw
2
这绝对是一个“更简洁”的答案。如果我是你,我会选择这个而不是我的。但是,请注意,有许多不同的对数函数将返回给定范围内的值。每个函数都具有高值比低值少的属性,但确切的数量将有所不同。我的答案与你在1.1到9.9之间的分布完全相同,只是“线性拉伸”。如果你想要完全一样的结果,请使用我的:否则,请使用这个。 - Jacob B
Jacob 是正确的。该实现将始终为您提供所提供范围内的对数分布。他的实现将扭曲分布。看起来他的代码偏爱较低的值,但这可能会受到我在运行模拟时选择的比例的影响。您需要检查在不同比例下获得的分布,以确定您想要哪种实现。 - Bill the Lizard
@John Rasch:感谢您修复我的括号。昨晚我在刻录DVD,无法抽出CPU周期来测试我的代码。 :) - Bill the Lizard

3

一种方法就是简单地缩放这些值:

function getRandomStrength($quality,$min,$max) {
    $rand = mt_rand()/mt_getrandmax();
    $value = round(pow(M_E, ($rand - 1.033) / -0.45), 1);
    $value = $value - 1.1
    $value = $value * ((max-min) / 8.8)
    $value = $value + $min
    return $value;
}

谢谢。我稍微调整了一下你的代码(一些疏忽)。现在正确了吗?http://paste.bradleygill.com/index.php?paste_id=9919 - caw

2

将分布缩放并位移至归一化范围内:

D(a,b) = (D(0,1)*(b-a))+a

要从原始函数D(c,d)中获取D(0,1),请执行反函数:

D(0,1) = (D(c,d)-c)/(d-c)

在您的情况下,D是原始函数(一个指数函数),a为1.5,b为8.5,c为1.1,d为9.9。


抱歉,我不是很明白。您能否再详细解释一下呢?这似乎比Jacob B的方法更复杂,对吧?整个函数术语是否乘以其他值(D*number)? - caw
理解这个例子的关键在于D并不是一个函数,而是一个统计分布(可以是均匀分布、指数分布等等)。我混淆了术语,试图让它更简单,但也许我错了 :-s - fortran

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接