要想完全了解float和double,学习其包装类Float和Double是最好的方法。
简单浏览Float的源码:
ublic final class Float extends Number implements Comparable<Float> {
private static final long serialVersionUID = -2671257302660747028L;
/**
* 正无穷大
*/
public static final float POSITIVE_INFINITY = 1.0f / 0.0f;
/**
* 负无穷大
*/
public static final float NEGATIVE_INFINITY = -1.0f / 0.0f;
/**
* 不是一个float数
*/
public static final float NaN = 0.0f / 0.0f;
/**
* 最大值
*/
public static final float MAX_VALUE = 0x1.fffffeP+127f; // 3.4028235e+38f
/**
* 最小正常值
* 原文: A constant holding the smallest positive normal value of type
*/
public static final float MIN_NORMAL = 0x1.0p-126f; // 1.17549435E-38f
/**
* 最小正非零值
* 原文: A constant holding the smallest positive nonzero value of type
*/
public static final float MIN_VALUE = 0x0.000002P-126f; // 1.4E-45f
/**
* 最大指数
*/
public static final int MAX_EXPONENT = 127;
/**
* 最小指数
*/
public static final int MIN_EXPONENT = -126;
/**
* 占用bit位
*/
public static final int SIZE = 32;
/**
* 占用字节数
*/
public static final int BYTES = SIZE / Byte.SIZE;//Byte.SIZE=8
/**
* 将float数值转成字符串
*/
public static String toString(float f) {
return FloatingDecimal.toJavaFormatString(f);
}
/**
* 将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);
}
/**
* 将字符串转成Float类型
*/
public static Float valueOf(String s) throws NumberFormatException {
return new Float(parseFloat(s));
}
/**
* 基本类型获取包装类型
*/
public static Float valueOf(float f) {
return new Float(f);
}
/**
* 将字符串转成float类型
*/
public static float parseFloat(String s) throws NumberFormatException {
return FloatingDecimal.parseFloat(s);
}
/**
* 判断是否为可用的float类型。Not-a-Number (NaN)。
*/
public static boolean isNaN(float v) {
return (v != v);
}
/**
* 是否为无穷大
*/
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;
}
/**
* The {@code Class} instance representing the primitive type
*/
@SuppressWarnings("unchecked")
public static final Class<Float> TYPE = (Class<Float>) Class.getPrimitiveClass("float");
/**
* 对floatToRawIntBits方法获取结果进行再处理,如果value为 NAN 返回 0x7fc00000。
* EXP_BIT_MASK = 2139095040 = 0111 1111 1000 0000 0000 0000 0000 0000;
* SIGNIF_BIT_MASK = 8388607= 0000 0000 0111 1111 1111 1111 1111 1111;
* positive infinity=0x7f800000= 0111 1111 1000 0000 0000 0000 0000 0000;
*/
public static int floatToIntBits(float value) {
int result = floatToRawIntBits(value);
// 如果value为 NAN 返回 0x7fc00000
if (((result & FloatConsts.EXP_BIT_MASK) == FloatConsts.EXP_BIT_MASK) &&
(result & FloatConsts.SIGNIF_BIT_MASK) != 0)
result = 0x7fc00000;
return result;
}
/**
* float和int都占用4个字节,以读取int字节方式,读去float字节,会获取一个整数。
* native 修饰的方法是java原生方法,方法体在jdk中,这里就不研究方法是如何实现的了。
*/
public static native int floatToRawIntBits(float value);
/**
* float和int都占用4个字节,以读取float字节方式,读去int字节,会获取一个float。
* native 修饰的方法是java原生方法,方法体在jdk中,这里就不研究方法是如何实现的了。
*/
public static native float intBitsToFloat(int bits);
/**
* 比较两个数
*/
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
// Cannot use floatToRawIntBits because of possibility of NaNs.
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)
}
/**
* 两个数之和
*/
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);
}
private final float value;
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 boolean isNaN() {
return isNaN(value);
}
public boolean isInfinite() {
return isInfinite(value);
}
public String toString() {
return Float.toString(value);
}
public byte byteValue() {
return (byte) value;
}
public short shortValue() {
return (short) value;
}
public int intValue() {
return (int) value;
}
public long longValue() {
return (long) value;
}
public float floatValue() {
return value;
}
public double doubleValue() {
return (double) value;
}
public int hashCode() {
return Float.hashCode(value);
}
public static int hashCode(float value) {
return floatToIntBits(value);
}
public int compareTo(Float anotherFloat) {
return Float.compare(value, anotherFloat.value);
}
public boolean equals(Object obj) {
return (obj instanceof Float)
&& (floatToIntBits(((Float) obj).value) == floatToIntBits(value));
}
}
首先要了解浮点数是如何存储的?什么是NaN?什么是规格化和非规格化?
通过上文的学习,上面的三个问题应该有了答案。
一、正无穷大、负无穷大和不是一个数
float POSITIVE_INFINITY = 1.0f / 0.0f;
float NEGATIVE_INFINITY = -1.0f / 0.0f;
float NaN = 0.0f / 0.0f;
浮点数是可以储存无穷大的,在整型中是不可能的,1/0肯定会出现异常。
NaN 不是一个有效数是一种特殊的现象,在整型中是不存在的。
float NaN1=Float.NaN;
float NaN2=Float.NaN+1;
//任何数加NaN还是NaN
System.out.println(NaN1);//NaN
System.out.println(NaN2);//NaN
//NaN通过>、<和==进行比较,结果都是false
System.out.println(NaN1>0);//false
System.out.println(NaN1==0);//false
System.out.println(NaN1<0);//false
System.out.println(NaN1==NaN1);//false
System.out.println(NaN1==NaN2);//false
System.out.println(Float.compare(NaN1,NaN1));//0
System.out.println(Float.compare(NaN1,NaN2));//0
System.out.println(Float.compare(NaN1,Float.MIN_VALUE));//1
System.out.println(new Float(NaN1).equals(NaN1));//true
System.out.println(new Float(NaN1).equals(NaN2));//true
@Test
public void testRabbit() throws Exception {
System.out.println("无穷大");
toBinaryString(1.0f / 0.0f);//无穷大
toBinaryString(1.0f / 0.0f - 100);//无穷大
toBinaryString(1.0f / 0.0f + 100);//无穷大
System.out.println("无穷小");
toBinaryString(-1.0f / 0.0f);//无穷小
toBinaryString(-1.0f / 0.0f - 100);//无穷小
toBinaryString(-1.0f / 0.0f + 100);//无穷小
System.out.println("NAN");
toBinaryString((1.0f / 0.0f) + (-1.0f / 0.0f));//无穷大+无穷小=NAN
toBinaryString(0.0f / 0.0f);//NAN
toBinaryString(0.0f / 0.0f + 100);//NAN
toBinaryString(-0.0f / 0.0f);//NAN
}
public void toBinaryString(float f) {
String s = Integer.toBinaryString(Float.floatToIntBits(f));
//f为正数时,符号位0,可能被省略,这里补上。
int n = 32 - s.length();
for (int i = 0; i < n; i++) {
s = "0" + s;
}
System.out.println(s);
}
二、最大值、最小正常值和最小正非零值
1、最大值 MAX_VALUE =3.4028235e+38f 最大值是如何算出来的?
最大指数是127,尾数(小数位)占23位,隐藏1位最高位1(规格化小数),当数最大时尾数23位全为1。
1.111 1111 1111 1111 1111 1111 * 2^127=1111 1111 1111 1111 1111 1111 *2^(-23)* 2^127=16777215*2^104
=3.4028234663852885981170418348452e+38
2、浮点数分为规格化和非规格化,因此出现了最小正常值和最小非零值。
在规格化情况下, 最小正值是 MIN_NORMAL = 1.17549435E-38f 。它是如何算出来的?
最小指数是-126,尾数(小数位)占23位,隐藏1位最高位1(规格化小数),当数最小时尾数23位全为0。
1.000 0000 0000 0000 0000 0000 * 2^(-126)=2^(-126)=1.1754943508222875079687365372222e-38
在非规格化情况下, 最小正值是 MIN_VALUE =1.4E-45f。它是如何算出来的?
指数是-126(不是-127),尾数(小数位)占23位,隐藏1位最高位0(非规格化小数)。当数最小时,尾数前22位全为0,最后一位是1。
0.000 0000 0000 0000 0000 0001 * 2^(-126)=2^(-149)=1.4012984643248170709237295832899e-45
三、toHexString方法解析
/**
* 将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);
}
在这个方法中,当为非规格化小数时,进入if语句。其实if和else语句都使用了Double.toHexString()方法。为什么要加这个if-else句语?
System.out.println(Float.toHexString(Float.MIN_VALUE));//0x0.000002p-126
System.out.println(Double.toHexString(Float.MIN_VALUE));0x1.0p-149
0x0.000002p-126=0x(2*16^(-6))p-126=0x(2^(-23))p-126=0x1p-149=0x1.0p-149
我们会发现Float.toHexString中的if句语没有对数值的大小产生影响,只是改变了表示形式。
Flaot的最小指数是-126,如果没有那个判断,指数会出现-149的情况,给人一种不爽的感觉。
if句语中做了什么?
只要v能进入if,其结果指数一定是-126,v=(v*2^126)p-126。v*2^126就小数G(|G|<1),再将G转成16进制就可以了,但是G不能用科学计数法表示。如果G还有指数,会导致最终指数不是-126。
如何将小数G转成16进制,但是不能用科学计数法?
Double.toHexString()可以将小数G转成16进制,但是不能保证不使用科学计数法。
System.out.println( Double.toHexString(0.00001));//0x1.4f8b588e368f1p-17
System.out.println( Double.toHexString(0.11));//0x1.c28f5c28f5c29p-4
Double.toHexString(G*Double.MIN_NORMAL)会出现什么样的效果? Double.MIN_NORMAL=1.0p-1022
G*Double.MIN_NORMAL<Double.MIN_NORMAL,Double.MIN_NORMAL的指数已经是最小,G*Double.MIN_NORMAL的指数将会是-1022,G在这种情况下不会在出现指数,但是Double.toHexString(G*Double.MIN_NORMAL)的结果将会是:***p-1022,我只需将p-1022替换成p-126。
Math.scalbd的含意: Math.scalb(x,y)=x*Math.pow(2,y) ; Math.scalb(3,4)=3*2^4=48;
Double最小指数:DoubleConsts.MIN_EXPONENT=-1022 ;Float最小指数FloatConsts.MIN_EXPONENT=-126。
Math.scalb((double)f,DoubleConsts.MIN_EXPONENT-FloatConsts.MIN_EXPONENT) 这语好难理解,转换一下,得到:
(double)f*2^(126)*2^(-1022)。
四、compare方法解析
/**
* 比较两个数
*/
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
// Cannot use floatToRawIntBits because of possibility of NaNs.
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)
}
//==比较0f和-0f是相等的,但compare方法比较时0f>-0f。
System.out.println(0f==-0f);//true
System.out.println(Float.compare(0f,-0f));//1
//==比较NaN和NaN是不相等的,但compare方法比较时相等。
System.out.println(Float.NaN==Float.NaN);//false
System.out.println(Float.NaN==Float.NaN+1);//false
System.out.println(Float.compare(Float.NaN,Float.NaN));//0
System.out.println(Float.compare(Float.NaN,Float.NaN+1));//0
//compare方法比较时,Float.NaN大于任何非NaN
System.out.println(Float.compare(Float.NaN,Float.MAX_VALUE));//1
System.out.println(Float.compare(Float.NaN,Float.POSITIVE_INFINITY));//1
五、equal方法解析
public boolean equals(Object obj) {
return (obj instanceof Float)
&& (floatToIntBits(((Float) obj).value) == floatToIntBits(value));
}
//NaN和NaN是相等的,0f和-0f不等
System.out.println(new Float(Float.NaN).equals(Float.NaN));//true
System.out.println(new Float(Float.NaN).equals(Float.NaN+1));//true
System.out.println(new Float(0f).equals(-0f));//false