最大范围的均匀分布浮点值?

时间:2013-03-22 21:44:20

标签: floating-point precision floating-point-precision

我试图更好地理解实数行上浮点值的分布。

我编写此代码来计算范围(-R,R)中均匀分布的可表示值的数量,其中R是 10 的幂(也尝试过权力2):

public class Foo {
    public static void main(String[] args)
    {
        for(int i=0; i<24; i++)
        {
            int count = 0;
            float R = (float) Math.pow(10, i); //(2<<i);
            float Rstep = Math.ulp(R);
            for(float x = -R; x <= R; x+=Rstep)
                count++;
            System.out.println(R+" "+count+" "+Math.ulp(R));
        }
    }
}

我对结果的差异感到惊讶,即

1.0 16777217 1.1920929E-7
10.0 20971521 9.536743E-7
100.0 26214401 7.6293945E-6
1000.0 32768001 6.1035156E-5
10000.0 20480001 9.765625E-4
100000.0 25600001 0.0078125
1000000.0 32000001 0.0625

因为我半信服自己,均匀分布的值的数量将是16777216(即,对于23位尾数,1 <&lt;&lt; 23,由于符号位加倍)。

在这个问题背后提出一些具体内容 - 我正在尝试构建一个模型(使用精确到几个数量级的SI单位,例如以千米到纳米的距离),但必须将其映射到浮动空间(用于加载到GPU)。由于这是一个科学模型,我需要了解精度丢失的地方。计划是将值捕捉到均匀分布的范围 - 所以从上面的表中捕捉到范围(-1000,1000)将给出32768001个确切的值。

对我而言,在这些范围内存在如此多的差异,以及为什么2个案例的权力有限,这似乎是违反直觉的。

有人能解释如何考虑这个吗?

欢呼声

1 个答案:

答案 0 :(得分:2)

你应该用十六进制打印浮点数,然后会更加清晰。

您对“16777216的估计(即23位尾数的1 <&lt;&lt; 23,由于符号位加倍)”只是您所期望的一半。最好的情况是从一个看起来像十六进制的-0x1.FFF ... pX的数字开始,也就是说,数字恰好低于2的幂。当重复添加初始ULP时,您确实将使用指数X遍历有效数字的所有值。当您推断时,这是1 <&lt;&lt;&lt; 23步。当你完成后,你将一半接近于零。相同数量的步骤将使您为零(指数低于X),然后再将步数加倍为正值。

因此,这是1 <&lt; 25(~32000000)左右的均匀间隔的浮子,可以在任何接近2的功率和其相反的功率之间找到。你得到的步数为1000,因为1000的功率只有两个1024。

最糟糕的情况,就像你注意到的那样,是从一个刚好超过2的幂的数字开始,比如0x1.00001pX。然后,您几乎没有使用指数X遍历值,而是立即开始访问具有较低指数的值。如果你从0x1.FFF ... pX

开始,你最终只能访问一半的值

注意:符号-0x1.123defpX应解释为-0x1.123def * 2 ^ X.也许您的编程语言接受它来输入和/或输出浮点值。要重新迭代,在尝试理解正在发生的事情时非常方便。