前置知识
原码: 最高位符号位,对齐它的为进行本身绝对值即可。
反码:
正数:反码和原码相同
负数:符号位一定是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 = 130
。130
用二进制表示是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的最小值是?
在Java
中Float.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_NOMAL
和MIN_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);
}
}