Java Floating-Point Number Intricacies
Thomas Wang, March 2000last update September 2000
Abstract
The semantic of Java floating point number generally follows the IEEE 754 Binary Floating-Point Arithmetic standard. The IEEE 754 standard provides for the definitions of floating-point infinities, negative infinities, negative zero, and NaN (not a number). In the context of Java, these entities are often confusing to typical programmers.
In this article, we will discuss the results of computing with these special floating-point entities. We will also point out some common Java floating-point number pit falls.
Introduction
The Java programming language provides two built-in classes for representing floating-point numbers: float, and double. The "float" class takes 4 bytes of storage, and have 23 binary digits of precision. The "double" class takes 8 bytes of storage, and have 52 binary digits of precision.
3.0d is a double precision floating-point number constant. 3.0, or alternatively 3.0f is a single precision floating-point number constant.
float f = 3.0f;
double d = 3.0d;
The Java core library also provides two wrapped classes java.lang.Float, and java.lang.Double. These two classes allow floating-point objects to be stored in Java collection objects, such as hash tables. These two classes also provides parsing, and conversion helper methods.
Float ff = new Float(1.0f); // creates a Java "Float" object
Double dd = new Double(2.0d); // creates a Java "Double" object
Special Floating-Point Number Entities
Not A Number
"NaN" stands for "not a number". "Nan" is produced if a floating point operation has some input parameters that cause the operation to produce some undefined result. For example, 0.0 divided by 0.0 is arithmetically undefined. Taking the square root of a negative number is also undefined.
0.0 / 0.0 -> NaN
Math.sqrt(-2.0) -> NaN
Operations involving NaN
Double.NaN + Double.NaN -> NaN
Float.NaN + 2.0 -> NaN
Float.NaN * 3.0 -> NaN
(0.0 / 0.0) * Float.POSITIVE_INFINITY -> NaN
Math.abs(0.0 / 0.0) -> NaN
(int) (Double.NaN) -> 0
All boolean operations involving "NaN" results in a false value.
Double.NaN > 1.0 -> false
Double.NaN < 1.0 -> false
Double.NaN == 1.0 -> false
Float.NaN < -3.0 -> false
Float.NaN > Float.POSITIVE_INFINITY -> false
Float.NaN < Float.POSITIVE_INFINITY -> false
(0.0 / 0.0) == (0.0 / 0.0) -> false
Infinity
"Infinity" is produced if a floating point operation creates such a large floating-point number that it cannot be represented normally. "Infinity" is a special value that represent the concept of positive infinity.
1.0 / 0.0 -> Infinity
Operations Involving Infinities
Double.POSITIVE_INFINITY == Double.POSITIVE_INFINITY -> true
Float.POSITIVE_INFINITY == Float.POSITIVE_INFINITY -> true
(1.0 / 0.0) + 2.0 -> Infinity
(1.0 / 0.0) * 0.5 -> Infinity
(1.0 / 0.0) * 0.0 -> NaN
(1.0 / 0.0) + (1.0 / 0.0) -> Infinity
(1.0 / 0.0) * (1.0 / 0.0) -> Infinity
(1.0 / 0.0) - (1.0 / 0.0) -> NaN
(1.0 / 0.0) / (1.0 / 0.0) -> NaN
(int) (1.0 / 0.0) -> 2147483647
Negative Infinity
"-Infinity" is produced if a floating point operation creates such an extremely negative floating-point number that it cannot be represented normally. "-Infinity" is a special value that represent the concept of negative infinity.
-1.0 / 0.0 -> -Infinity
Operations Involving Negative Infinity
- Double.POSITIVE_INFINITY == Doublle.NEGATIVE_INFINITY -> true
Float.NEGATIVE_INFINITY < 1.0 -> true
(-1.0 / 0.0 ) + 2.0 -> -Infinity
(-1.0 / 0.0) == (-1.0 / 0.0) -> true
(-1.0 / 0.0) - (-1.0 / 0.0) -> NaN
(-1.0 / 0.0) * 0.5 -> -Infinity
(-1.0 / 0.0) * 0.0 -> NaN
Math.abs(-1.0 / 0.0) -> Infinity
(int) (-1.0 / 0.0) -> -2147483648
Negative Zero
"-0.0" is produced when a floating-point operation results in a negative floating-point number so close to 0 that cannot be represented normally.
-2.0 / Float.POSITIVE_INFINITY -> -0.0
"-0.0" is numerically identical to "0.0". However, some operations involving "-0.0" are different than the same operation with "0.0".
(-0.0) == 0.0 -> true
2.0 / (0.0) -> Infinity
2.0 / (-0.0) -> -Infinity
Operations Involving Negative Zero
0.0 > (-0.0) -> false
(-0.0) * (-0.0) -> 0.0
3.0 + (-0.0) -> 3.0
4.0 * (-0.0) -> -0.0
0.0 - 0.0 -> 0.0
(-0.0) - (-0.0) -> 0.0
(-0.0) + (-0.0) -> -0.0
(-0.0) + 0.0 -> 0.0
0.0 + (-0.0) -> 0.0
(-0.0) - 0.0 -> -0.0
- (-0.0) -> 0.0
- (0.0) -> -0.0
0.0 / (-0.0) -> NaN
Comparing Java "Float" Objects
Comparing two Java "Float" objects can have different semantics than comparing two Java "float" values. Recall the "float" class is a Java primitive class, while java.lang.Float is a subclass of "Object".
A "NaN" value is not equal to itself. However, a "NaN" Java "Float" object is equal to itself. The semantic is defined this way, because otherwise "NaN" Java "Float" objects cannot be retrieved from a hash table.
(new Float(0.0 / 0.0)).equals(new Float(0.0 / 0.0)) -> true
For the class java.lang.Float, objects are ordered from lowest to highest: -Infinity, negative numbers, -0.0, 0.0, positive numbers, Infinity, NaN. "java.lang.Double" objects are identically ordered.
(new Float(0.0)).equals(new Float(-0.0)) -> false
(new Float(-1.0 / 0.0)).compareTo(new Float(-3.0)) -> -1
(new Float(-3.0)).compareTo(new Float(-0.0)) -> -1
(new Float(-0.0)).compareTo(new Float(0.0)) -> -1
(new Float(0.0)).compareTo(new Float(3.0)) -> -1
(new Float(3.0)).compareTo(new Float(1.0 / 0.0)) -> -1
(new Float(1.0 / 0.0)).compareTo(new Float(0.0 / 0.0)) -> -1
Some Actual Pitfalls
Wrong Way to Implement abs()
This is the wrong way:
(f >= 0.0) ? f : - f
What if 'f' is -0.0? Since 0.0 is equal to -0.0, the above expression would return the incorrect value of -0.0, versus the correct value of 0.0.
The correct expression is:
(f <= 0.0) ? 0.0 - f : f
Be very careful when you are optimizing a floating point expression. For example, if you optimized the above expression to:
(f <= 0.0) ? - f : f
Then you introduced a bug that causes abs(0.0) to return -0.0.
Danger of Floating-Point Number Optimization
We have already seen a case where (0.0 - f) is not equal to (- f).
! (a < b) does not imply that (a >= b).
! (1.0 < NaN) -> true
(1.0 >= NaN) -> false
One page 308 of the book "The Java Language Specification", it talks in more detail of the danger of optimizing floating-point expressions.
Assuming A Floating-Point Value Is Equal To Itself
Well, a "NaN" value is not equal to itself. For similar reason, assuming a number subtracting itself must equal to 0.0 is wrong. "NaN" - "NaN" still yields "NaN". "Infinity" - "Infinity" yields "NaN", although two Infinities are equal to each other.
Not Checking for NaN
public employee(float monthly_salary)
{
if (monthly_salary < 0.0)
throw IllegalArgumentException("illegal monthly salary");
this.yearly_salary = 12.0 * monthly_salary;
}
The above piece of code would not catch the mistake of using a "NaN" as an input argument. The code below would catch it.
public employee(float monthly_salary)
{
if (monthly_salary >= 0.0)
{
this.yearly_salary = 12.0 * monthly_salary;
}
else throw IllegalArgumentException("illegal monthly salary");
}
Looking at the fixed code, what should we do if the input argument is "Infinity"? Depending on the API's specification, we can do a number of different things. The point is that any time we are dealing with floating-point numbers, we should think about the cases dealing with "NaN", "Infinity", "-Infinity", and "-0.0".
References
James Gosling, Bill Joy, Guy Steele, "The Java Language Specification", Addison Wesley, (1996)
IEEE, "ANSI/IEEE Std 754-1985, An American National Standard IEEE Standard for Binary Floating-Point Arithmetic", (1985)
分享到:
相关推荐
stylelint-config-concentric-order 此配置根据验证 CSS 属性的顺序。 除了您自己的规则(或来自可共享配置的规则)之外,强烈建议您使用它,因为它只与排序有关。 该配置适用于stylelint --fix和以自动对您的 CSS ...
将其导入到您的文件中import 'package:concentric_transition/concentric_transition.dart'; 特征 同心PageView 同心飞剪机 同心PageRoute 用法 使用ConcentricPageView小部件 import 'package:concentric_...
matlab跳过代码直接运行适应性风险偏好 从以下位置安装:并按照自述文件中的...此示例在同心环世界中演化了一个64千机器人群的行为,可以轻松替代其他世界或行为。基本用法包括: 为包含所有要演化的变量的行为编写脚
CCTag库 检测由同心圆组成的CCTag标记。 在CPU和GPU中均实现。 该库是该文件的实现: Lilian Calvet,Pierre Gurdjos,Carsten Griwodz,Simone Gasparini。 在高度挑战性的条件下对圆形基准的检测和精确定位。...
运行: ./bin/concentric-clock_dbg Windows(在Win7 x64上测试) 将放在文件夹.\lib\ [可选]将SFML .dll文件放在.\bin目录中,以便更轻松地执行二进制文件,因为lib是动态链接的。 如果使用的是mingw32,请运行...
Not-so-concentric Spherical Capacitor (Michigan Tech) 3.13. Parallel Plate Capacitor with Solid Dielectric (Stony Brook, 3.14. Michigan Tech, Michigan) 49 50Parallel Plate Capacitor in Dielectric Bath...
concentric_wheel
抽象精品ppt模板concentric_wheel147
ConcentricGridView是一个网格系统,UICollectionViewLayout使用它来使用不同的分布算法(同心均匀分布算法(CUDA)和同心一致分布算法(CCDA))以同心方式对UICollectionViewCell进行布局。 您可以在下面以相同的...
这是一篇用Huashu Dou提出的新理论——能量梯度理论来求解稳定性问题的文章
同心对比圆图像特征的优点是易于制造,易于从图像中提取,鲁棒性提取(找到了真实目标,而发现了很少的错误目标),这是一个被动特征,其质心完全不变。三个平移和一个旋转自由度,几乎与其余两个旋转自由度不变。 ...
The Er-doped concentric-cores dispersion compensating fiber (EDDCF) has been demonstrated. The rare earth has been doped as a ring around the inner core. We have obtained 14-dB gain at 1550 nm (using ...
三维平板金属透镜性能研究,冯迪,张春熹,一种亚波长平面金属透镜(SPMLs)用于实现可见光范围的远场光聚焦,基于宽度调制的同心圆银膜结构。每一个金属环的宽度是变化的,以��
霍夫变换,同心圆检测,比较有用。文档中有详细的解释
Annular field aberrations of a three-reflection concentric system, which are composed of two spherical mirrors, are analyzed. An annular field with a high level of aberration correction exists near ...
A robust design for a photonic crystal fiber (PCF) based on pure silica with small normal dispersion and high nonlinear coefficient for its dual concentric core structure is presented. This design is ...
Generation of concentric perfect Poincare beams
Concentric-Project
Draw concentric squares 30 A circle from an oval 32 A circle from an arc 34 Three arc ellipses 35 Polygons 36 A star polygon 37 Cloning and resizing stars 39 Chapter 3: Handling Text 43 ...
The dispersion compensation properties of dual-concentric core photonic crystal fibers are theoretically investigated in this letter. The effects of geometric structure on the dispersion properties of...