3

这可能是 x86 FPU 专家的问题:

我正在尝试编写一个在 [min,max] 范围内生成随机浮点值的函数。问题是我的生成器算法(浮点 Mersenne Twister,如果你好奇的话)只返回 [1,2) 范围内的值 - 即,我想要一个包容性的上限,但我的“源”生成值是从一个排他的上限。这里的问题是底层生成器返回一个 8 字节的双精度,但我只想要一个 4 字节的浮点数,而且我使用的是默认的 FPU 舍入模式 Nearest。

我想知道的是,在这种情况下,截断本身是否会导致我的返回值在 FPU 内部 80 位值足够接近时包含最大值,或者我是否应该在将最大值乘以之前增加最大值的有效位[1,2) 中的中间随机数,或者我是否应该更改 FPU 模式。当然,或者任何其他想法。

这是我目前使用的代码,我确实验证了 1.0f 解析为 0x3f800000:

float MersenneFloat( float min, float max )
{
    //genrand returns a double in [1,2)
    const float random = (float)genrand_close1_open2(); 
    //return in desired range
    return min + ( random - 1.0f ) * (max - min);
}

如果它有所作为,这需要在 Win32 MSVC++ 和 Linux gcc 上工作。另外,使用任何版本的 SSE 优化会改变这个问题的答案吗?

编辑:答案是肯定的,在这种情况下,从 double 到 float 的截断足以导致结果包含 max。有关更多信息,请参阅 Crashworks 的答案。

4

3 回答 3

4

SSE 操作将巧妙地改变该算法的行为,因为它们没有中间的 80 位表示——数学实际上是在 32 位或 64 位中完成的。好消息是,您可以轻松地对其进行测试,并通过简单地将 /ARCH:SSE2 命令行选项指定给 MSVC 来查看它是否会更改您的结果,这将导致它使用 SSE 标量操作而不是 x87 FPU 指令来处理普通浮点数学。

我不确定整数边界周围的确切舍入行为是什么,但你可以测试看看当 1.999.. 从 64 位舍入到 32 位时会发生什么,例如

static uint64 OnePointNineRepeating = 0x3FF FFFFF FFFF FFFF // exponent 0 (biased to 1023), all 1 bits in mantissa
double asDouble = *(double *)(&OnePointNineRepeating);
float asFloat = asDouble;
return asFloat;

编辑,结果:原始发帖人运行了这个测试,发现在截断的情况下,1.99999 在有和没有 /arch:SSE2 的情况下都将四舍五入为 2。

于 2009-03-13T22:03:39.127 回答
0

如果您确实调整了舍入以使范围的两端都包括在内,那么这些极端值的可能性不只是任何非极端值的一半吗?

于 2009-03-13T21:35:29.553 回答
0

使用截断,您将永远不会包含最大值。

你确定你真的需要最大值吗?从字面上看,您将完全达到最大值的可能性几乎为 0。

也就是说,您可以利用您放弃精度的事实并执行以下操作:

float MersenneFloat( float min, float max )
{
    double random = 100000.0; // just a dummy value
    while ((float)random > 65535.0)
    {
        //genrand returns a double in [1,2)
        double random = genrand_close1_open2() - 1.0; // now it's [0,1)
        random *= 65536.0; // now it's [0,65536). We try again if it's > 65535.0
    }
    //return in desired range
    return min + float(random/65535.0) * (max - min);
}

请注意,现在,每次调用 MersenneFloat 时,它都有可能多次调用 genrand。因此,您已经放弃了封闭区间的可能性能。由于您正在从 double 向下转换为 float,因此您最终不会牺牲任何精度。

编辑:改进算法

于 2009-03-13T21:44:02.637 回答