首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

浮点数(3)

浮点数(3)

最小的精度单位[size=1.0625]实数是非常密集的。任意两个不同的实数中间都可以出现其他实数。但浮点数则不是这样。对于浮点数和双精度数,也存在下一个浮点数;连续的浮点数和双精度数之间存在最小的有限距离。nextUp()方法返回比第一个参数大的最近浮点数。例如,清单 2 打印出所有在 1.0 和 2.0 之间的浮点数:
清单 2. 计算浮点数数量

[size=0.875]1


[size=0.875]2


[size=0.875]3


[size=0.875]4


[size=0.875]5


[size=0.875]6


[size=0.875]7


[size=0.875]8


[size=0.875]9


[size=0.875]10


[size=0.875]11


[size=0.875]12


[size=0.875]13


[size=0.875]14


[size=0.875][size=0.875]public class FloatCounter {

[size=0.875]   public static void main(String[] args) {
[size=0.875]       float x = 1.0F;
[size=0.875]       int numFloats = 0;
[size=0.875]       while (x <= 2.0) {
[size=0.875]           numFloats++;
[size=0.875]           System.out.println(x);
[size=0.875]           x = Math.nextUp(x);
[size=0.875]       }
[size=0.875]       System.out.println(numFloats);
[size=0.875]   }

[size=0.875]}




[size=1.0625]结果是 1.0 和 2.0 之间包含 8,388,609 个浮点数;虽然很多,但还不至于是无穷多的实数。相邻数字的距离为 0.0000001。这个距离称为 ULP,它是 最小精度单位(unit of least precision)最后位置单位(unit in the last place)的缩略。
[size=1.0625]如果需要向后查找小于指定数字的最近浮点数,则可以改用 nextAfter()方法。第二个参数指定是否查找在第一个参数之上或之下的最近数字:

[size=0.875]1


[size=0.875]2


[size=0.875][size=0.875]public static double nextAfter(float start, float direction)
[size=0.875] public static double nextAfter(double start, double direction)




[size=1.0625]如果 direction大于 start,则 nextAfter()返回在 start之上的下一个数字。如果 direction小于 start,则 nextAfter()返回在 start之下的下一个数字。如果 direction等于 start,则 nextAfter()返回 start本身。
[size=1.0625]这些方法在某些建模或图形工具中是非常有用的。从数字上来说,您可能需要在 ab之间的 10,000 个位置上提取样例值,但如果您具备的精度仅能识别 ab之间的 1,000 个独立的点,那么有十分之九的工作是重复的。您可以只做十分之一的工作,但又获得相同的结果。
[size=1.0625]当然,如果一定需要额外的精度,则可以选择具有高精度的数据类型,比如 double或 BigDecimal。例如,我曾经在 Mandelbrot 集合管理器看见过这种情况。在其中可以放大曲线图,让其落在最近的两个双精度数之间。Mandelbrot 集合在各个级别上都是非常细微和复杂的,但是 float或 double可以在失去区分相邻点的能力之前达到这个细微的级别。
[size=1.0625]Math.ulp()返回一个数字和距其最近的数字之间的距离。清单 3 列出了 2 的各种幂次方的 ULP:
清单 3. 浮点数 2 的幂次方的 ULP

[size=0.875]1


[size=0.875]2


[size=0.875]3


[size=0.875]4


[size=0.875]5


[size=0.875]6


[size=0.875]7


[size=0.875]8


[size=0.875]9


[size=0.875][size=0.875]public class UlpPrinter {

[size=0.875]   public static void main(String[] args) {
[size=0.875]       for (float x = 1.0f; x <= Float.MAX_VALUE; x *= 2.0f) {
[size=0.875]           System.out.println(Math.getExponent(x) + "\t" + x + "\t" + Math.ulp(x));
[size=0.875]       }
[size=0.875]   }

[size=0.875]}




[size=1.0625]下面给出了一些输出:

[size=0.875]1


[size=0.875]2


[size=0.875]3


[size=0.875]4


[size=0.875]5


[size=0.875]6


[size=0.875]7


[size=0.875]8


[size=0.875]9


[size=0.875]10


[size=0.875]11


[size=0.875]12


[size=0.875]13


[size=0.875]14


[size=0.875]15


[size=0.875]16


[size=0.875][size=0.875]0   1.0   1.1920929E-7
[size=0.875] 1   2.0   2.3841858E-7
[size=0.875] 2   4.0   4.7683716E-7
[size=0.875] 3   8.0   9.536743E-7
[size=0.875] 4   16.0  1.9073486E-6
[size=0.875] ...
[size=0.875] 20  1048576.0   0.125
[size=0.875] 21  2097152.0   0.25
[size=0.875] 22  4194304.0   0.5
[size=0.875] 23  8388608.0   1.0
[size=0.875] 24  1.6777216E7 2.0
[size=0.875] 25  3.3554432E7 4.0
[size=0.875] ...
[size=0.875] 125 4.2535296E37    5.0706024E30
[size=0.875] 126 8.507059E37     1.0141205E31
[size=0.875] 127 1.7014118E38    2.028241E31




[size=1.0625]可以看到,对于比较小的 2 的幂次方,浮点数是非常精确的。但是在许多应用程序中,在数值约为 220时,这一精度将出现问题。在接近浮点数的最大极限时,相邻的值将被 千的七乘方(sextillions)隔开(事实上可能更大一点,但我找不到词汇来表达)。
[size=1.0625]如清单 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 时才会出现这种情况,但这也是个问题。
山不在高,有仙则名;水不在深,有龙则灵。
返回列表