美文网首页
JDK之Float源码解析

JDK之Float源码解析

作者: luoyoub | 来源:发表于2018-05-04 18:54 被阅读0次

    概述

    Java的Float类主要的作用就是对基本类型float进行封装,提供了一些处理float类型的方法,比如float到String类型的转换方法或String类型到float类型的转换方法,当然也包含与其他类型之间的转换方法

    java float类型用IEEE754标准规定;

    float占用4个字节,包括:

    • 1bit(符号位):0表示正数,1表示负数;
    • 8bits(指数位):float的偏移量为2^8 - 1,double的偏移量为2^11 - 1;
    • 23bits(尾数位):实际尾数部分中的小数点后的数值,规约浮点数使用标准的二进制科学计数法表示,其尾数范围在 [1,2),非规约浮点数的尾数部分范围在(0,1)


      这里写图片描述

    示例:

    8.25 的 float 表示
    整数8的二进制:1000
    小数0.25的二进制:.01
    8.25整体的二进制:1000.01 → 1.00001 * 2^3
    小数点左移 3 位,所以指数部分(3 + 127) = 130,二进制是 10000010
    尾数:去掉小数点前面的1,为 00001,补充到 23 位,000 0100 0000 0000 0000 0000
    最终 8.25 在内存中存储的二进制是:0100 0001 0000 0100 0000 0000 0000 0000
    
    9.5 的 float 表示
    9.5的二进制:1001.1 -> 1.0011 * 2^3
    指数位是 (3 + 127)=130,二进制 10000010
    尾数是 0011 000000 0000000000 000
    最终 9.5 在内存中存储的二进制是:010000010 0011 000000 0000000000 000,和程序打印出来的一致。
    

    类继承关系:

    public final class Float extends Number implements Comparable<Float> {
        public static final float POSITIVE_INFINITY = 1.0f / 0.0f; // 正无穷大
        public static final float NEGATIVE_INFINITY = -1.0f / 0.0f; // 负无穷大
    
        public static final float NaN = 0.0f / 0.0f; // Not a Number(不是数)(输出就是NaN)
    
        // 指数部分的最大值(指数位的长度1个字节):127,最小值为-126
        public static final int MAX_EXPONENT = 127;
        public static final int MIN_EXPONENT = -126;
    
        // 一个float占4个字节(32位)
        public static final int SIZE = 32;
    }
    

    说明:这是java的规定,没必要深究为什么1.0/0.0不报错,不过1/0肯定报错

    关于IEEE 754

    在看Float前需要先了解IEEE 754标准,该标准定义了浮点数的格式还有一些特殊值,它规定了计算机中二进制与十进制浮点数转换的格式及方法。规定了四种表示浮点数值的方法,单精确度(32位)、双精确度(64位)、延伸单精确度(43位以上)与延伸双精确度(79位以上)。多数编程语言支持单精确度和双精确度,这里讨论的Float就是Java的单精确度的实现

    类方法: {#类方法}

    1.toString(float f):

    public String toString() {
        return Float.toString(value);
    }
    public static String toString(float f) {
        return FloatingDecimal.toJavaFormatString(f);
    }
    

    FloatingDecimal:的作用是将float格式化转换,即什么时候用数字显示(位数小于8位),什么时候用指数显示(位数>=8位)
    更加详细的在API中有说明

    2.toHexString(float f):转成16进制的字符串(用科学计数法表示)

    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);
    }
    

    3.两个valueOf():将字符串/浮点数转换成Float类型的对象

    public static Float valueOf(String s) throws NumberFormatException {
        return new Float(parseFloat(s));
    }
    public static Float valueOf(float f) {
        return new Float(f);
    }
    

    4.parseFloat(String s):和valueOf重复了

    public static float parseFloat(String s) throws NumberFormatException {
        return FloatingDecimal.parseFloat(s);
    }
    

    5.isNaN(float v):判断是不是一个‘不是数’(NaN和任何东西都不想等,包括他自己)

    public static boolean isNaN(float v) {
            return (v != v);
        }
    

    6.isInfinite(float v):判断是不是正无穷或者负无穷(这两个数使计算没有任何意义)

    public static boolean isInfinite(float v) {
        return (v == POSITIVE_INFINITY) || (v == NEGATIVE_INFINITY);
    }
    

    7.floatToRawIntBits(float value) floatToIntBits(float value) intBitsToFloat(int bits):

    • 根据 IEEE 754 的浮点“单一形式”中的位布局,返回指定浮点值的表示形式
    • 根据 IEEE 754 的浮点“单一形式”中的位布局,返回指定浮点值的表示形式,并保留非数字 (NaN) 值。
    • 返回对应于给定的位表示形式的 float 值。该参数被认为是符合 IEEE 754 的浮点“单一形式”中的位布局规定的浮点值表示形式
    public static native float intBitsToFloat(int bits);
     public static native int floatToRawIntBits(float value);
     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;
        }
    

    8.compare(float f1, float f2):比较两个float的大小

    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)
    }
    

    float二进制表示

    int i = Float.floatToIntBits(8.25f);
    System.out.println(Integer.toBinaryString(i)); // output==>1000001000001000000000000000000
    

    精度损失

    看下面的程序:

    float f = 2.2f;  
    double d = (double) f;  
    System.out.println(f);  
    System.out.println(d);
    

    打印出来的结果:

    2.2
    2.200000047683716
    

    为什么会出现这种情况?

    对于不能用二进制表示的 十进制小数,二进制小数位会进行循环,所以会损失精度。比如下面的语句会输出 true:

    System.out.println(2.2f == 2.20000001f);
    

    测试

    float num = 4.0f / 0.0f;
    System.err.println(num); // java中规定分母不能为0,但是浮点数计算中不抛异常
    
    output==>Infinity
    

    相关文章

      网友评论

          本文标题:JDK之Float源码解析

          本文链接:https://www.haomeiwen.com/subject/oqkjrftx.html