Float类源码学习

要想完全了解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、double存储方式

通过上文的学习,上面的三个问题应该有了答案。

一、正无穷大、负无穷大和不是一个数

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

 

 

 

 

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值