快速业务通道

Java Math 类中的新功能,第 2 部分: 浮点数 - 编程入门网

作者 佚名技术 来源 NET编程 浏览 发布时间 2012-06-17
大,它们之间的浮点数就会越来 越少。例如,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 时才会出现这种情况,但这也是 个问题。

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));

根据期望值不同,这个值可以是万亿分之一,也可以是数百万。

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

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

实际上,这个循环将在一个固定的点上停下来,准确的数字是 16,777,216。这个数字等 于 224,在这个点上,ULP 比增量大。

scalb

Math.scalb(x, y) 用 2y 乘以 x,scalb 是 “scale binary(二进法)” 的缩写。

public static double scalb(float f, int scaleFactor) public static double scalb(double d, int scaleFactor)

Java Math 类中的新功能,第 2 部分: 浮点数(5)

时间:2011-04-30 IBM Elliotte Rusty Harol

例如,Math.scalb(3, 4) 返回 3 * 24,即 3*16,结果是 48.0。也可以使 用 Math.scalb() 来实现 getMantissa():

public static double getMantissa(double x) {    int exponent = Math.getExponent(x);    return x / Math.scalb(1.0, exponent); }

Math.scalb() 和 x*Math.pow(2, scaleFactor) 的区别是什么?实际上,最终的结果是 一样的。任何输入返回的值都是完全一样的。不过,性能方面则存在差别。Math.pow() 的性 能是非常糟糕的。它必须能够真正处理一些非常少见的情况,比如对 3.14 采用幂 -0.078。 对于小的整数幂,比如 2 和 3(或以 2 为基数,这比较特殊),通常会选择完全错误的算 法。

我担心这会对总体性能产生影响。一些编译器和 VM 的智能程度比较高。一些优化器会将 x*Math.pow(2, y) 识别为特殊情况并将其转换为 Math.scalb(x, y) 或类似的东西。因此性 能上的影响体现不出来。不过,我敢保证有些 VM 是没有这么智能的。例如,使用 Apple 的 Java 6 VM 进行测试时,Math.scalb() 几乎总是比 x*Math.pow(2, y) 快两个数量级。当然 ,这通常不会造成影响。但是在特殊情况下,比如执行数百万次求幂运算时,则需要考虑能 否转换它们以使用 Math.scalb()。

Copysign

Math.copySign() 方法将第一个参数的标记设置为第二个参数的标记。最简单的实现如清 单 4 所示:

清单 4. 可能实现的 copysign 算法

public static double copySign(double magnitude, double sign) {    if (magnitude == 0.0) return 0.0;    else if (sign < 0) {    if (magnitude < 0) return magnitude;    else ret

凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!

分享到: 更多

Copyright ©1999-2011 厦门凌众科技有限公司 厦门优通互联科技开发有限公司 All rights reserved

地址(ADD):厦门软件园二期望海路63号701E(东南融通旁) 邮编(ZIP):361008

电话:0592-5908028 传真:0592-5908039 咨询信箱:web@lingzhong.cn 咨询OICQ:173723134

《中华人民共和国增值电信业务经营许可证》闽B2-20100024  ICP备案:闽ICP备05037997号