本文参考B站up主free-coder

前置知识

原码: 最高位符号位,对齐它的为进行本身绝对值即可。
反码:
正数:反码和原码相同
负数:符号位一定是1,其余位对原码取反。
补码:
正数:补码和原码相同
负数:符号位一定是1,反码+1

int是怎么存的

要想了解flaot 是怎么存的就得先了解整数是怎么存的

二进制第一位表示的是符号位。其中正数的符号位为0,负数的符号位为1

+1  原码  0000 0000 ... 0001         
-1  原码  1000 0000 ... 0001
    反码  1111 1111 ... 1110
    补码  1111 1111 ... 1111

Q:计算机中负数都是用补码的形式表示表示,为什么不能就用1000 0000 ... 0001 这种原码的形式表示?

A:如果用原码表示的话,-2 应该是1000 0000 ... 0010,理论上 -2+1=-1 但如果直接在二进制上+1 ,变为 1000 0000 ... 0011 这样就变成 -3了,

所以计算机在进行二进制运算的时候会用补码进行运算

-2  原码 1000 0000 ... 0010
    反码 1111 1111 ... 1101
    补码 1111 1111 ... 1110
对补码进行+1运算 -2 + 1 = -1  
-1  补码 1111 1111 ... 1111

int的最大值怎么算?

int 占4个字节 1Byte = 8bit ,所以int占32位

最大 0111 1111 ... 1111 2^0 + 2^1 +...+2^30 = 2^31 - 1

最小 理论上最小是符号位为1 其余都是为1 取补码是 1000 0000 ... 0001 ,发现再-1好像还能更小

1000 0000 ... 0000

我们可以用IDEA进行验证

打开Integer.MAX_VALUE的源码可以看到 他的十六进制是0x7fffffff第一位为什么是7?因为 其对应的二进制0111 1111 ... 1111 ,前4位化为16进制正好是7。

代码验证

public class FloatTest {
    public static void main(String[] args) {
        test1();
    }
    public static void test1(){
        //二进制
        int i = 0b01111111111111111111111111111111;
        int j = 0b11111111111111111111111111111111;
        //十六进制
        int k = 0x7fffffff;
        System.out.println(Integer.MAX_VALUE == i);
        System.out.println(Integer.MAX_VALUE == k);
        System.out.println(j == -1);
    }
}

float是如何存储的

float的内存结构如下图,由符号位,指数位,尾数位构成

举个栗子:

10用二进制表示:  
2^3 2^2 2^1 2^0
1   0   1   0
如果是10.5用二进制怎么表示?  Q:10的基础上加上0.5
2^3 2^2 2^1 2^0 2^-1 2^-2
1    0    1    0  .1    
如果是10.625用二进制怎么表示?  Q:10.5的基础上加上0.125(2^-3)
2^3 2^2 2^1 2^0 2^-1 2^-2 2^-3
1   0    1   0  .1    0      1

10.625为例

将整个数右移(小数点左移,但一般认为小数点的位置不变去移动数字)

一般右移表示+ 左移表示- 移动了3位记为+3

1010.101 变成1.010101

其中中间指数的位置 为【移动的数值(可正可负)+127

所以 3+127 = 130130用二进制表示是1000 0010

剩下的23位尾数为小数点后取23位, 即0101 0100 0000 0000 0000 000

代码验证

public class FloatTest {
    public static void main(String[] args) {
        test1();
    }
    public static void test1(){
        //二进制
        int i = 0b01000001001010100000000000000000;
        //将二进制转成float
        System.out.println(Float.intBitsToFloat(i));
        //float有时也会写成16进制
        //1010.101
        float f =0xa.ap0f;//加一个p表示移动多少位
        //当小数点的位置进行移动
        //1.010101
        float f1 =0x1.54p3f;
        System.out.println(f);
        System.out.println(f1);
    }
}

结果都是10.625,没什么问题

float的最大值怎么取?

符号位是0

位移次数越多,向右移128位

尾数部分越大越好

0 1111 1111 1111 1111 1111 1111 1111 111

是这样吗?

代码验证

public class FloatTest {
    public static void main(String[] args) {
        test1();
    }
    public static void test1(){
        //理论float最大值
        int i = 0b01111111111111111111111111111111;
        System.out.println(Float.intBitsToFloat(i));
    }
}

输出结果为NaN,程序没有报错

其实NaN是float的保留字,并不是最大值

通过IDEA的提示功能可以看到看到最大移动位置只能移动127位,并不能移动128位,所以指数位为

1111 1110 最大数为0 1111 1110 1111 1111 1111 1111 1111 111

再验证一下

public class FloatTest {
    public static void main(String[] args) {
        test1();
    }
    public static void test1(){
        //float最大值
        int i = 0b01111111011111111111111111111111;

        System.out.println(Float.intBitsToFloat(i) == Float.MAX_VALUE);
    }
}

结果为true

换算成16进制就是0x7f7fffff

float的最小值是?

JavaFloat.MIN_VALUE并不是最小值,而指的是正数的最小值,float肯定有正有负,真正的最小值是

-Float.MAX_VALUE

那最小的正数怎么算?

符号位    指数位      尾数位
0        0000 0001  0000 0000 0000 0000 0000 000

代码验证

public class FloatTest {
    public static void main(String[] args) {
        test1();
    }
    public static void test1(){
        int i1 = 0b01111111011111111111111111111111;
        System.out.println(Float.intBitsToFloat(i1) == Float.MAX_VALUE);

        int i2 = 0b00000000100000000000000000000000;
        System.out.println(Float.intBitsToFloat(i2) == Float.MIN_NORMAL);
    }
}

MIN_NOMALMIN_VALUE有什么区别?

MIN_NOMAL 是1.0左移126位

MIN_VALUE 如果这个数字特的小,移动了126位还是没有到1,有效位仍然为0,这个时候往后取23位有有效数字,这个float依然是合法的。

0 .0000 0000 0000 0000 0000 001 MIN_VALUE

1 .0000 0000 0000 0000 0000 000 MIN_NOMAL

float的精度问题

前面的例子10.625例子比较特殊,刚好可以用2的次幂叠加来表示,但大部分的数字只能无限接近,而无法刚好表示,这样就会出现精度丢失。

public class FloatTest {
    public static void main(String[] args) {
        test1();
    }
    public static void test1(){
        float f1 = 10.4f;
        float f2 = 10.40000000000000000000000f;

        System.out.println(f1 == f2);
    }
}
最后修改:2022 年 04 月 21 日
如果觉得我的文章对你有用,请随意赞赏