对于x86 FPU专家来说,这可能是一个问题:

我正在尝试编写一个函数,该函数生成范围为[min,max]的随机浮点值。问题是我的生成器算法(如果您想知道,浮点数Mersenne Twister)仅返回[1,2]范围内的值-即,我想要一个包含范围的上限,但是我的“源”生成的值是从专属上限。这里的问题是底层生成器返回一个8字节的double,但是我只想要4字节的float,并且我使用的是默认的FPU舍入模式Nearest。

我想知道的是,在这种情况下,截断本身是否会导致FPU内部80位值足够接近时我的返回值包含max,或者我是否应该在将max乘以x之前增加其有效位数? [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的答案。

最佳答案

SSE操作将巧妙地改变此算法的行为,因为它们没有中间的80位表示形式-数学实际上是用32位或64位完成的。好消息是,您可以通过简单地将/ ARCH:SSE2命令行选项指定为MSVC来轻松测试它并查看它是否改变了结果,这将导致它使用SSE标量ops代替x87 FPU指令进行普通浮点运算数学。

我不确定确切的四舍五入行为是围绕整数边界的,但是您可以测试一下,例如,将1.999 ..通过64位从32位舍入为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和不带/ arch:SSE2的情况下均向上舍入为2。

10-08 19:18