看不到的Java细节:浮点运算

来源:互联网 发布:淘宝回复买家评论话语 编辑:程序博客网 时间:2024/06/07 01:25
http://hi.baidu.com/lszhuhaichao/blog/item/2ecf5acda47aa65d0eb34551.html 2010-04-03 20:21

看不到的Java细节:浮点运算

1、 浮点运算是不精确度的

规则:在需要精确的地方不要使用浮点,应该使用一个一个整数类型或BigDecimal。要避免浮点类型的循环索引。要避免在浮点变量上使用++操作符,因为这些操作对多数的浮点数都不起任何作用。避免测试浮点值是否相等。宁愿用double,而不用float

doublefloat数值类来表示无穷大是可以的。这是因为一个浮点数值越大,它和其后继数值之间的间隔就越大。浮点数的这种分布式用固定数量的有效位来表示它们的必然结果。对一个足够大的浮点数加1不会改变它的值,因为1不足以“填补它与其后继者之间的空隙”。

浮点数操作数返回的是最接近其精确数学结果的浮点数值。一旦毗邻的浮点数值之间的距离大于2,那么对其中的一个浮点数值加1将不会产生任何效果,因为其结果没有达到两个数值之间的一半。对于float类型,加1不会产生任何效果的最小级数是2^25,即33554432;而对于double类型,最小级数是2^54,即1.8e16

毗邻的浮点数值之间的距离被称为一个ulp,他是最下单位(unit in the last place)的缩写。

此外,将一个很小的浮点数加到一个很大的浮点数上,将不会改变大浮点数的值。所以我们应该记住二进制浮点算术只是对实际算术的一种近似。

2、 NaN不等于任何浮点数值,包括它自身

规则:要避免测试浮点数的相对性。这么做并不总能避免问题,但至少是一个良好的开端。

NaN不等于任何浮点数值,包括它自身在内。“==”不满足自反性。

任何浮点操作,只要它的一个或多个操作数为NaN,那么其结果为NaN

一旦一个计算产生了NaN,它就损坏了,没有任何更进一步的计算可以修复这样的损坏。

3、intfloat、从longfloat以及从longdouble的转换时有损精度的

规则:要避免整型和浮点型混合的计算。要优选整型算术而不是浮点型算术。“==”不满足“传递性”,这是由于可能出现类型转换。

4、 BigDecimal(double)构造器返回的是其浮点型参数的精确值

规则:应该总是使用BigDecimal(String)构造器,而永远不要使用BigDecimal(double)

5、 混合型计算容易令人迷茫

规则:要避免混合类型的计算。当把?:操作符作用于数字操作符时,第二个和第三个操作数要使用相同的数字类型。宁愿使用不变的变量,不愿使用内置的幻数。

不要使用异常控制循环;应该只位异常条件而使用异常。

要意识到逻辑ANDOR操作符的存在,并且不要因无意识的无用而受害。

6、 操作符的操作数是从左到右计算的

规则:要避免在同一个表达式中对相对的变量多次赋值。尤其是在同一个表达式中放入多重复合赋值操作符特别令人迷茫。

7、 操作符的优先级并不总是很明显

规则:要使用括号而不是空格来让优先级变得明显。要用具名的常量变量来替换内联的常量表达式。

8、 操作符==!=在包装的的原生类型上执行引用比较

规则:要想强制进行值比较,需要在比较之前将一个操作数赋值或转型成恰当的原生类型。

5.0版本中,自动包装和自动反包装被添加到了Java语言当中。<=操作符在原始数字类型集上是反对称的,但是现在它还应用在被包装的数字类型上(被包装类型的数字类型有:ByteCharacterShortIntegerLongFloatDouble)。<=操作符在这些类型的操作数上不是反对称的,因为Java的判等操作符(==!=)在作用于对象引用时,执行的是引用ID的比较,而不是值的比较。

9、 常量变量在所用的地方是内联的

规则:要避免导出常量域,除非它们表示的是永远都不会变化的真正的常量。可以使用一个恒等函数将一个表达式变成非常亮。

Java是在运行时对类进行装卸的,所以它总是访问最新版本的类。

对于常量域的引用会在编译期被转化为它们所表示的常量的值。这样的域从技术上讲,被称作常量变量(constant varicable),其定义就是,一个在编译期被常量表达式初始化的final的原生类型或String类型变量。

在这里还有要了解编译期常量表达式,所谓编译期常量表达式,就是其值在编译期间被确定,而在任何程序被执行之前。这里需要指出的是null不是一个编译期常量表达式。

5.0版本中引入的枚举常量,虽然有这样一个名字,但是它们不是常量变量。你可以在枚举类型中加入枚举常量,对它们重新排序,甚至可以移除没有用的枚举常量,并且并不需要重新编译客户端。

10、              操作数&I即使在作用于布尔类型的数值时,也要同时计算其两个操作数。

规则:要避免将&I作用于布尔类型的操作数。对有意义的使用要加以注释。

注意,不要使用异常类控制循环;应该只为异常条件而使用异常。

&操作符除了位AND运算之外,还有的功能就是布尔操作符,功能和&&基本相同。差别就在于:&操作符总是计算它的两个操作数,而&&操作符在其左边的操作数被计算为false时,就不在计算右边的操作数。