本系列是对JDK源码中8种数据类型的简单了解。
JDK源码解析(5)——Short、Long、Double、Float
一、Short
1、shortcache的初始值在-128 —— 127,不同于Integer,shortcache不可调整大小。
decode
//decode方法将字符串解码为Short,
//此方法接受十进制字符串,十六进制字符串(用0x\0X#标识),八进制字符串(用0标识),
//但是解码后的值必须在[-32768,32767]这一区间内,否则抛出NumberFormatException异常。
public static Short decode(String nm) throws NumberFormatException {
int i = Integer.decode(nm);
if (i < MIN_VALUE || i > MAX_VALUE)
throw new NumberFormatException(
"Value " + i + " out of range from input " + nm);
return valueOf((short)i);
}
reverseBytes
//将short二进制的高八位和低八位交换。
public static short reverseBytes(short i) {
return (short) (((i & 0xFF00) >> 8) | (i << 8));
}
toUnsignedInt
// 将short类型的数转换为无符号的int类型。
public static int toUnsignedInt(short x) {
return ((int) x) & 0xffff;
}
toUnsignedLong
//将short类型的数转换为无符号的long类型。
public static long toUnsignedLong(short x) {
return ((long) x) & 0xffffL;
}
二、Long
类的定义
public final class Long extends Number implements Comparable<Long>
valueOf
//推荐使用 valueOf 方法,少使用 parseLong 方法
//valueOf 方法会从缓存中去拿值,如果命中缓存,会减少资源的开销,parseLong 方法就没有这机制。
public static Long valueOf(long l) {
final int offset = 128;
// 先在缓冲池中取
if (l >= -128 && l <= 127) {
// 这里+offest是要计算出索引,因为cache[0]=-127
return LongCache.cache[(int)l + offset];
}
return new Long(l);
}
bitCount
//返回二进制中1的个数。
public static int bitCount(long i) {
i = i - ((i >>> 1) & 0x5555555555555555L);
i = (i & 0x3333333333333333L) + ((i >>> 2) & 0x3333333333333333L);
i = (i + (i >>> 4)) & 0x0f0f0f0f0f0f0f0fL;
i = i + (i >>> 8);
i = i + (i >>> 16);
i = i + (i >>> 32);
return (int)i & 0x7f;
}
三、Double
类的定义
public final class Double extends Number implements Comparable<Double>
max
//a与b都为0.0时,a为-0则返回b
public static double max(double a, double b) {
if (a != a)
return a; // a is NaN
if ((a == 0.0d) &&
(b == 0.0d) &&
(Double.doubleToRawLongBits(a) == negativeZeroDoubleBits)) {
// Raw conversion ok since NaN can't map to -0.0.
return b;
}
return (a >= b) ? a : b;
}
min
//a与b都为0.0时,b为-0则返回b
public static double min(double a, double b) {
if (a != a)
return a; // a is NaN
if ((a == 0.0d) &&
(b == 0.0d) &&
(Double.doubleToRawLongBits(b) == negativeZeroDoubleBits)) {
// Raw conversion ok since NaN can't map to -0.0.
return b;
}
return (a <= b) ? a : b;
}
double的精度丢失问题
1、精度丢失
当我们在计算 0.1+0.2 时,结果不是 0.3,而是:0.30000000000000004
2、分析
由于我们输入的十进制的 double 类型的数据在进行计算的时候,计算机会先将其转换为二进制数据,然后再进行相关的运算。然而在十进制转二进制的过程中,有些十进制数是无法使用一个有限的二进制数来表达的,换言之就是转换的时候出现了精度的丢失问题
3、解决
将 double 类型的数据转换成 BigDecimal 来进行运算,最后再转换成 double 类型的数据。
double d1 = 0.1, d2 = 0.2;
System.out.println(d1 + d2);
System.out.println(new BigDecimal(d1).add(new BigDecimal(d2)).doubleValue());
System.out.println(BigDecimal.valueOf(d1).add(BigDecimal.valueOf(d2)).doubleValue());
System.out.println(new BigDecimal(Double.toString(d1)).add(new BigDecimal(Double.toString(d2))).doubleValue());
//print
0.30000000000000004
0.30000000000000004
0.3
0.3
为什么会出现用BigDecimal计算出 0.30000000000000004 ,这个值呢。我们看下面的源码:
// 方式一
public BigDecimal(double val) {
this(val,MathContext.UNLIMITED);
}
// 方式二
public BigDecimal(String val) {
this(val.toCharArray(), 0, val.length());
}
// 方式三(其实底层就是方式二)
public static BigDecimal valueOf(double val) {
return new BigDecimal(Double.toString(val));
}
我们可以看到,如果一的构造方式去实现,将会用double类型来计算,如果我们用方式二去构造或者使用方法三valueOf(本质上是方法二),计算就不会产生精度丢失问题。
四、Float
类的定义
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);
}
public static float parseFloat(String s) throws NumberFormatException {
return FloatingDecimal.parseFloat(s);
}
valueOf
//Float调用valueOf都是new实例。
public static Float valueOf(String s) throws NumberFormatException {
return new Float(parseFloat(s));
}
public static Float valueOf(float f) {
return new Float(f);
}
compareTo
//f1小于f2则返回-1,反之则返回1。
//无法通过上述直接比较时则使用floatToIntBits方法分别将f1和f2转成IEEE 754标准对应的整型数,然后再比较。相等则返回0,否则返回-1或1。注意:正0比负0大;NaN比任何非NaN的数都大。
public int compareTo(Float anotherFloat) {
return Float.compare(value, anotherFloat.value);
}
public static int compare(float f1, float f2) {
if (f1 < f2)
return -1; // Neither val is NaN, thisVal is smaller
if (f1 > f2)
return 1; // Neither val is NaN, thisVal is larger
// 不能使用floatToRawIntBits方法,因为可能为NaN.
int thisBits = Float.floatToIntBits(f1);
int anotherBits = Float.floatToIntBits(f2);
return (thisBits == anotherBits ? 0 : // Values are equal
(thisBits < anotherBits ? -1 : // (-0.0, 0.0) or (!NaN, NaN)
1)); // (0.0, -0.0) or (NaN, !NaN)
}
五、Infinity和NaN
Infinity
infinity表示无穷,如果我们用浮点数除以‘0’,一般用infinity表示正无穷,-infinity 表示负无穷
Float d1 = 1.00f, d2 = 0.00f;
System.out.println(d1/d2);
//print
Infinity
Float d1 = -1.00f, d2 = 0.00f;
System.out.println(d1/d2);
//print
-Infinity
NaN
NaN是“IEEE 754”协议中规定了几种特殊值,
1. 第一种 指数是0并且尾数的小数部分是0,这个数±0(和符号位相关)
2. 第二种 指数2e-1并且尾数的小数部分是0,这个数是±∞(同样和符号位相关)
3. 第三种 指数2e-1并且尾数的小数部分非0,这个表示为不是一个数(NaN)
Float d1 = 0.00f, d2 = 0.00f;
System.out.println(d1/d2);
//print
NaN
/**
NaN的产生情形:
1. 至少有一个参数是NaN的运算
2. 不定式
2.1 下列除法运算:0/0、∞/∞、∞/−∞、−∞/∞、−∞/−∞
2.2 下列乘法运算:0×∞、0×−∞
2.3 下列加法运算:∞ + (−∞)、(−∞) + ∞
2.4 下列减法运算:∞ - ∞、(−∞) - (−∞)
3. 产生复数结果的实数运算。例如:
3.1 对负数进行开偶次方的运算
3.2 对负数进行对数运算
3.3 对正弦或余弦到达域以外的数进行反正弦或反余弦运算
**/