这可能是一个x86 FPU专家一个问题:

我试图写产生在范围[最小值,最大值]的随机浮点值的函数。问题是,我的发电机算法(浮点梅森倍捻机,如果你好奇)仅在区间[1,2)返回值 - 即,我希望有一个包容性的上限,但我的“源”产生的价值从异上限。这里美中不足的是,底层的发生器返回一个8字节双,但我只想要一个4字节的浮点以及我使用的最近的默认FPU舍入模式。

我想知道的是截断本身在这种情况下,是否会导致我的返回值是包容性最大的当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优化的任何版本更改应答这个?

修改答案是肯定的,截断在这种情况下,从双浮动足以导致的结果是包括性的最大的。见Crashworks的回答为多。

有帮助吗?

解决方案

在SSE OPS会微妙地改变该算法的行为,因为他们不具有中间的80位表示 - 的数学真正在32或64位完成。好消息是,你可以很容易地对其进行测试,看看它是否通过简单地指定/ ARCH改变你的结果:SSE2命令行选项来MSVC,这将导致它使用SSE标OPS代替的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将四舍五入到2具有和不/拱:SSE2

其他提示

如果这样做调整的舍入,使得不包括该范围的两个端部,将这些极端值不是只有一半的几率为任何非极端者的?

通过截断,你永远不会是包容性最大的。

你确定你真的需要最大?从字面上有一个几乎为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。所以,你已经放弃了闭区间可能的性能。由于要从双向下转换到浮动,你最终没有牺牲精度。

编辑:改进算法

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top