JVM源码解读-Float类
1.类图
2.存储位置
- Float类中的静态属性存储在方法区中的静态区。
- 通过new Float()方法创建出来的对象存储在堆区。
3.了解IEEE 754
3.1 IEEE 754简介
在看Float前需要先了解IEEE 754标准,该标准定义了浮点数的格式还有一些特殊值,它规定了计算机中二进制与十进制浮点数转换的格式及方法。规定了四种表示浮点数值的方法,单精确度(32位)、双精确度(64位)、延伸单精确度(43位以上)与延伸双精确度(79位以上)。
多数编程语言支持单精确度和双精确度,该标准的全称为IEEE二进制浮点数算术标准(ANSI/IEEE Std 754-1985),又称IEC 60559:1989,微处理器系统的二进制浮点数算术(本来的编号是IEC 559:1989)。后来还有“与基数无关的浮点数”的“IEEE 854-1987标准”,有规定基数为2跟10的状况。最新标准是“ISO/IEC/IEEE FDIS 60559:2010”。
Float就是Java的单精度实现。
3.2 IEEE 754单精度浮点数表示
浮点数由三部分组成,分别是符号位s、指数e和尾数f。
在IEEE754标准中,一个规格化的32位浮点数x的真值表示为
x = (−1)s∗(1.f)∗2(e−127)
e = E - 127
其中尾数域所表示的值是1.f。由于规格化的浮点数的尾数域最左位(最高有效位)总是1,故这一位经常不予存储,而认为隐藏在小数点的左边。于是用23位字段可以存储24位有效数。
我们举个例子来看,二进制的“01000001001101100000000000000000”表示的浮点数是啥?
符号位为0,表示正数。
指数为“10000010”,减去127后为3。
尾数对应的值为“1.011011”。
于是最终得到浮点数为“1011.011”,转成十进制为“11.375”。
4.源码解读
4.1 属性说明
public final class Float extends Number implements Comparable<Float> {
// System.out.println(Float.POSITIVE_INFINITY == Float.intBitsToFloat(0x7f800000)); // true
// System.out.println(Float.POSITIVE_INFINITY); ==> Infinity
// 用来表示正无穷大,按照IEEE 754浮点标准规定,任何有限正数除以0为正无穷大,正无穷的值为0x7f800000。
public static final float POSITIVE_INFINITY = 1.0f / 0.0f;
// System.out.println(Float.NEGATIVE_INFINITY == Float.intBitsToFloat(0xff800000)); // true
// System.out.println(Float.NEGATIVE_INFINITY); // -Infinity
// 用来表示负无穷大,任何有限负数除以0为负无穷的,负无穷的值为0xff800000。
public static final float NEGATIVE_INFINITY = -1.0f / 0.0f;
// System.out.println(Float.isNaN(Float.intBitsToFloat(0x7fc00000))); // true
// System.out.println(Float.intBitsToFloat(0x7fc00000)); // NaN
// NaN 用来表示处理计算中出现的错误情况,比如0除以0或负数平方根。对于单精度浮点数,IEEE 标准规定 NaN 的指数域全为 1,且尾数域不等于零的浮点数。它并没有要求具体的尾数域,所以 NaN 实际上不非是一个,而是一族。Java这里定义的值为0x7fc00000。
public static final float NaN = 0.0f / 0.0f;
// System.out.println(Float.MAX_VALUE == Float.intBitsToFloat(0x7f7fffff)); // true
// System.out.println(Float.intBitsToFloat(0x7f7fffff)); // 3.4028235E38
// 用来表示最大的浮点数值,它定义为0x1.fffffeP+127f,这里0x表示十六进制,1.fffffe表示十六进制的小数,P表示2,+表示几次方,这里就是2的127次方,最后的f是转成浮点型。所以最后最大值为3.4028235E38。
public static final float MAX_VALUE = 0x1.fffffeP+127f; // 3.4028235e+38f
// System.out.println(Float.MIN_NORMAL == Float.intBitsToFloat(0x00800000)); // true
// System.out.println(Float.intBitsToFloat(0x00800000)); // 1.17549435E-38
// 1.6开始存在
// 用来表示最小标准值,它定义为0x1.0p-126f,这里其实就是2的-126次方的了,值为1.17549435E-38f。
public static final float MIN_NORMAL = 0x1.0p-126f; // 1.17549435E-38f
// System.out.println(Float.MIN_VALUE == Float.intBitsToFloat(0x1)); // true
// System.out.println(Float.intBitsToFloat(0x1)); // 1.4E-45
// 用来表示浮点数最小值,它定义为0x0.000002P-126f,最后的值为1.4e-45f
public static final float MIN_VALUE = 0x0.000002P-126f; // 1.4e-45f
// System.out.println(Math.getExponent(Float.MAX_VALUE) == Float.MAX_EXPONENT); // true
// System.out.println(Math.getExponent(Float.MAX_VALUE)); // 127
// 1.6开始
// 用来表示指数的最大值,这里定为127,这个也是按照IEEE 754浮点标准的规定。
public static final int MAX_EXPONENT = 127;
// System.out.println(Math.getExponent(Float.MIN_NORMAL) == Float.MIN_EXPONENT); // true
// System.out.println(Float.MIN_EXPONENT); // -126
// 1.6开始
// 用来表示指数的最小值,按照IEEE 754浮点标准的规定,它为-126。
public static final int MIN_EXPONENT = -126;
// 用来表示二进制float值的比特数,值为32,静态变量且不可变。
public static final int SIZE = 32;
// 用来表示二进制float值的字节数,值为SIZE除于Byte.SIZE,结果为4字节,表示存储一个Float类型的变量占用4字节。
public static final int BYTES = SIZE / Byte.SIZE;
}
4.2 方法说明
Float构造方法
Float构造方法有3个,第一个是将float但精度浮点数转为Float值,第二个是将double值的双精度浮点数转为单精度浮点数,该转化可能出现精度丢失的情况。
第三个构造方法是将字符串转为单精度浮点数。
public final class Float extends Number implements Comparable<Float> {
public Float(float value) {
this.value = value;
}
public Float(double value) {
this.value = (float)value;
}
public Float(String s) throws NumberFormatException {
value = parseFloat(s);
}
}
toHexString方法
- 该方法是将浮点数转为16进制数的字符串
Floating-point Value | Hexadecimal String |
---|---|
1.0 | 0x1.0p0 |
0.25 | 0x1.0p-2 |
Float.MAX_VALUE | 0x1.fffffep127 |
Float.MIN_VALUE | 0x0.000002p-126 |
public final class Float extends Number implements Comparable<Float> {
public static String toHexString(float f) {
if (Math.abs(f) < FloatConsts.MIN_NORMAL
&& f != 0.0f ) {// float subnormal
// Adjust exponent to create subnormal double, then
// replace subnormal double exponent with subnormal float
// exponent
String s = Double.toHexString(Math.scalb((double)f,
/* -1022+126 */
DoubleConsts.MIN_EXPONENT-
FloatConsts.MIN_EXPONENT));
return s.replaceFirst("p-1022$", "p-126");
}
else // double string will be the same as float string
return Double.toHexString(f);
}
}
public class FloatDemoTest {
@Test
public void testToHexString() {
System.out.println(Float.toHexString(1.0f)); //0x1.0p0
}
}
valueOf方法
改方法有两个,一个是将字符串转为单精度浮点数,一个是将float值转化为Float对象
public final class Float extends Number implements Comparable<Float> {
public static Float valueOf(String s) throws NumberFormatException {
return new Float(parseFloat(s));
}
public static Float valueOf(float f) {
return new Float(f);
}
}
public class FloatDemoTest {
@Test
public void testValueOf() {
System.out.println(Float.valueOf(1.01f)); // 1.01
System.out.println(Float.valueOf("1.01")); // 1.01
System.out.println(Float.valueOf("+1.01f")); // 1.01
System.out.println(Float.valueOf("-1.01f")); // -1.01
System.out.println(Float.valueOf("1.01F")); // 1.01
System.out.println(Float.valueOf("1.01d")); // 1.01
System.out.println(Float.valueOf("1.01I")); // java.lang.NumberFormatException: For input string: "1.01I"
}
}
parseFloat方法
该是Java中的内置方法,该方法返回一个新的float,该新float初始化为指定的String表示的值,这由Float类的valueOf方法完成。
public final class Float extends Number implements Comparable<Float> {
public static float parseFloat(String s) throws NumberFormatException {
return FloatingDecimal.parseFloat(s);
}
}
isNaN方法
- 该方法是判断是否是非数字的值(NAN), NaN是Not a Number的缩写。
public final class Float extends Number implements Comparable<Float> {
public boolean isNaN() {
return isNaN(value);
}
public static boolean isNaN(float v) {
return (v != v);
}
}
isInfinite与isInfinite方法
isInfinite()方法用于检查此Float对象的无穷大(即正无穷大或负无穷大)
isFinite() 方法如果传递的参数是有限浮点数,则返回 true,否则返回 false(在 NaN 和无穷大参数的情况下)。
public final class Float extends Number implements Comparable<Float> {
public static boolean isInfinite(float v) {
return (v == POSITIVE_INFINITY) || (v == NEGATIVE_INFINITY);
}
public static boolean isFinite(float f) {
return Math.abs(f) <= FloatConsts.MAX_VALUE;
}
}
public class FloatDemoTest {
@Test
public void testInfiniteAndFinite() {
System.out.println(Float.isInfinite(Float.POSITIVE_INFINITY)); // true
System.out.println(Float.isInfinite(0.05f)); // false
System.out.println(Float.isFinite(0.05f)); // true
System.out.println(Float.isFinite(Float.POSITIVE_INFINITY)); // false
}
}
floatToIntBits方法
Float类中的floatToIntBits()方法是Java中的内置函数,它根据IEEE 754浮点“single format”位布局返回指定浮点值的表示形式。
返回值:该函数返回表示浮点数的整数位。以下是特殊情况:
- 如果参数为正无穷大,则结果为0x7f800000。
- 如果参数为负无穷大,则结果为0xff800000。
- 如果参数为NaN,则结果为0x7fc00000。
public final class Float extends Number implements Comparable<Float> {
public static int floatToIntBits(float value) {
int result = floatToRawIntBits(value);
// Check for NaN based on values of bit fields, maximum
// exponent and nonzero significand.
if ( ((result & FloatConsts.EXP_BIT_MASK) ==
FloatConsts.EXP_BIT_MASK) &&
(result & FloatConsts.SIGNIF_BIT_MASK) != 0)
result = 0x7fc00000;
return result;
}
}
sum/max/min方法
- sum方法是用来计算两个float值之和。
- max方法是用来查找两个float值的最大值。
- min方法是用来查找两个float值的最小值。
public final class Float extends Number implements Comparable<Float> {
public static float sum(float a, float b) {
return a + b;
}
public static float max(float a, float b) {
return Math.max(a, b);
}
public static float min(float a, float b) {
return Math.min(a, b);
}
}
floatToRawIntBits/intBitsToFloat native方法()
- Float类中的floatToRawIntBits()方法是Java中的内置函数,该函数根据IEEE 754浮点“single format”位布局返回指定浮点值的表示形式,并保留Not-a-Number(NaN)值。
返回值:该函数返回代表浮点数的位。但是,有3种特殊情况:
* 如果参数为正无穷大,则结果为0x7f800000。
* 如果参数为负无穷大,则结果为0xff800000。
* 如果参数为NaN,则结果为0x7fc00000。
- Java Float 类的 intBitsToFloat() 方法返回与给定位表示相关的浮点值。根据 IEEE 754 浮点 'single format' 位布局,传递的参数被视为浮点值的表示。
此方法返回具有相同位模式的浮点值。
* 如果传递的参数为 0X7f800000,则返回的结果为正无穷大。
* 如果传递的参数为 0Xff800000,则返回的结果为负无穷大。
* 如果传递的参数在 0x7f800001 到 0x7fffffff 之间的范围内或在 0xff800001 到 0xffffffff 之间的范围内,则返回的结果为 Nan。
public final class Float extends Number implements Comparable<Float> {
public static native int floatToRawIntBits(float value);
public static native float intBitsToFloat(int bits);
}
5.说明
- 需要精确计算时不要使用float和double,如果需要精度计算,请使用BigDecimal
- 不能用浮点数作为循环变量,浮点数不能为循环因子,精度问题会导致 (float)2000000000 == 2000000050为true
- 浮点型数据判断相等不能直接使用,应采用如下方式
float a =...;
float b =...;
if (Math.abs(a-b) < 1E-6f) {
...
}