加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

最小的精度单位

(2013-11-17 10:28:48)
标签:

java学习

如何学习java

学习java哪里好

清软国际java学习

东方清软

教育

分类: JAVA学习

最小的精度单位 java学习 清软国际 软件工程师 如何学习java 学习java哪里好 东方清软java培训 清软国际java学习 计算机软件学习

实数是非常密集的。任意两个不同的实数中间都可以出现其他实数。但浮点数则不是这样。对于浮点数和双精度数,也存在下一个浮点数;连续的浮点数和双精度数之间存在最小的有限距离。nextUp() 方法返回比第一个参数大的最近浮点数。例如,清单 2 打印出所有在 1.0 和 2.0 之间的浮点数:java学习 清软国际 软件工程师 如何学习java 学习java哪里好 东方清软java培训 清软国际java学习 计算机软件学习

计算浮点数数量
    
public class FloatCounter {
    public static void main(String[] args) {
        float x = 1.0F;
        int numFloats = 0;
        while (x <= 2.0) {
            numFloats++;
            System.out.println(x);
            x = Math.nextUp(x);
        }
        System.out.println(numFloats);
    }
}java学习 清软国际 软件工程师 如何学习java 学习java哪里好 东方清软java培训 清软国际java学习 计算机软件学习

结果是 1.0 和 2.0 之间包含 8,388,609 个浮点数;虽然很多,但还不至于是无穷多的实数。相邻数字的距离为 0.0000001。这个距离称为 ULP,它是最小精度单位(unit of least precision) 或最后位置单位(unit in the last place)的缩略。

如果需要向后查找小于指定数字的最近浮点数,则可以改用 nextAfter() 方法。第二个参数指定是否查找在第一个参数之上或之下的最近数字:java学习 清软国际 软件工程师 如何学习java 学习java哪里好 东方清软java培训 清软国际java学习 计算机软件学习

public static double nextAfter(float start, float direction)
public static double nextAfter(double start, double direction)

如果 direction 大于 start,则 nextAfter() 返回在 start 之上的下一个数字。如果 direction 小于 start,则 nextAfter() 返回在 start 之下的下一个数字。如果 direction 等于 start,则 nextAfter() 返回 start 本身。

这些方法在某些建模或图形工具中是非常有用的。从数字上来说,您可能需要在 a 和 b 之间的 10,000 个位置上提取样例值,但如果您具备的精度仅能识别 a 和 b 之间的 1,000 个独立的点,那么有十分之九的工作是重复的。您可以只做十分之一的工作,但又获得相同的结果。java学习 清软国际 软件工程师 如何学习java 学习java哪里好 东方清软java培训 清软国际java学习 计算机软件学习

当然,如果一定需要额外的精度,则可以选择具有高精度的数据类型,比如 double 或 BigDecimal。例如,我曾经在 Mandelbrot 集合管理器看见过这种情况。在其中可以放大曲线图,让其落在最近的两个双精度数之间。Mandelbrot 集合在各个级别上都是非常细微和复杂的,但是 float 或 double 可以在失去区分相邻点的能力之前达到这个细微的级别。

Math.ulp() 返回一个数字和距其最近的数字之间的距离。清单 3 列出了 2 的各种幂次方的 ULP:java学习 清软国际 软件工程师 如何学习java 学习java哪里好 东方清软java培训 清软国际java学习 计算机软件学习

浮点数 2 的幂次方的 ULP
    
public class UlpPrinter {
    public static void main(String[] args) {
        for (float x = 1.0f; x <= Float.MAX_VALUE; x *= 2.0f) {
            System.out.println(Math.getExponent(x) + "\t" + x + "\t" + Math.ulp(x));
        }
    }
}java学习 清软国际 软件工程师 如何学习java 学习java哪里好 东方清软java培训 清软国际java学习 计算机软件学习

下面给出了一些输出:

  1.0   1.1920929E-7
  2.0   2.3841858E-7
  4.0   4.7683716E-7
  8.0   9.536743E-7
  16.0  1.9073486E-6
...java学习 清软国际 软件工程师 如何学习java 学习java哪里好 东方清软java培训 清软国际java学习 计算机软件学习

20  1048576.0   0.125
21  2097152.0   0.25
22  4194304.0   0.5
23  8388608.0   1.0
24  1.6777216E7 2.0
25  3.3554432E7 4.0
...java学习 清软国际 软件工程师 如何学习java 学习java哪里好 东方清软java培训 清软国际java学习 计算机软件学习

125 4.2535296E37    5.0706024E30
126 8.507059E37     1.0141205E31
127 1.7014118E38    2.028241E31
                 

可以看到,对于比较小的 2 的幂次方,浮点数是非常精确的。但是在许多应用程序中,在数值约为 220 时,这一精度将出现问题。在接近浮点数的最大极限时,相邻的值将被 千的七乘方(sextillions)隔开(事实上可能更大一点,但我找不到词汇来表达)。java学习 清软国际 软件工程师 如何学习java 学习java哪里好 东方清软java培训 清软国际java学习 计算机软件学习

如清单 3 所示,ULP 的大小并不是固定的。随着数字变大,它们之间的浮点数就会越来越少。例如,10,000 和 10,001 之间只有 1,025 个浮点数;它们的距离是 0.001。在 1,000,000 和 1,000,001 之间仅有 17 个浮点数,它们的距离是 0.05。精度与数量级成反比关系。对于浮点数 10,000,000,ULP 的精确度变为 1.0,超过这个数之后,将有多个整数值映射到同一个浮点数。对于双精度数,只有达到 4.5E15 时才会出现这种情况,但这也是个问题。java学习 清软国际 软件工程师 如何学习java 学习java哪里好 东方清软java培训 清软国际java学习 计算机软件学习

Math.ulp() 为测试提供一个实用的用途。很明显,我们一般不会比较两个浮点数是否完全相等。相反,我们检查它们是否在一定的容错范围内相等。例如,在 JUnit 中,像以下这样比较预期的实际浮点值:

assertEquals(expectedValue, actualValue, 0.02);

这表明实际值与预期值的偏差在 0.02 之内。但是,0.02 是合理的容错范围吗?如果预期值是 10.5 或 -107.82,则 0.02 是完全可以接受的。但当预期值为几十亿时,0.02 则与 0 没有什么区别。通常,就 ULP 进行测试时考虑的是相对错误。一般选择的容错范围在 1 至 10 ULP 之间,具体情况取决于计算所需的精度。例如,下面指定实际结果必须在真实值的 5 个 ULP 之内:

assertEquals(expectedValue, actualValue, 5*Math.ulp(expectedValue));

根据期望值不同,这个值可以是万亿分之一,也可以是数百万。java学习 清软国际 软件工程师 如何学习java 学习java哪里好 东方清软java培训 清软国际java学习 计算机软件学习

注:

浮点数的有限精度会导致一个难以预料的结果:超过某个点时,x+1 == x 便是真的。例如,下面这个简单的循环实际上是无限的:

for (float x = 16777213f; x < 16777218f; x += 1.0f) {
    System.out.println(x);
}

实际上,这个循环将在一个固定的点上停下来,准确的数字是 16,777,216。这个数字等于 224,在这个点上,ULP 比增量大。java学习 清软国际 软件工程师 如何学习java 学习java哪里好 东方清软java培训 清软国际java学习 计算机软件学习

学习java哪里好?
学习java的视频:http://i.youku.com/u/UMTIwMTg2NjczMg 视频密码:sinojava

java学习 清软国际 软件工程师 如何学习java 学习java哪里好 东方清软java培训 清软国际java学习 计算机软件学习

0

阅读 收藏 喜欢 打印举报/Report
前一篇:尾数和指数
后一篇:scalb和Copysign
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有