二进制 binary
八进制 octal
十进制 decimal
十六进制 hex
基本数据类型
boolean 1bit
byte 1byte(8bit) -2^(8-1)~2^(8-1)-1 -128~127
short 2byte -2^15~2^15-1 -32768-32767
char 2byte 在Java中最大值为'\uFFFF'
int 4byte -2,147,483,648~2,147,483,647 约21亿
long 8byte -9,223,372,036,854,775,808~9,22 3,372, 036,8 54,77 5,807 约922 亿亿
原码反码补码的数学定义:
若x使用n位二进制存储
下面举例都以n为8说明
原码
2^(n-1)>x>=0时原码为x
-2^(n-1)<x<=0时原码为2^(n-1)-x
例如8原码为 0000 1000
-8原码为 1000 1000 (128-(-8)) 如果看做无符号数是 136
反"码
2^(n-1)>x>=0时反码为x
-2^(n-1)<x<=0时反码为2^n - 1 + x 这里2^n也称为模
例如8的反码为0000 1000
-8的反码为 1111 0111 (256-1+(-8)) 如果看做无符号数是 247
补码
2^(n-1)>x>=0时 补码为x
-2^(n-1)<x<=0时补码为2^n+x
例如8的补码为 0000 1000
-8的补码为 1111 1000 *(256+(-8)) 如果把其对应的二进制序列看做无符号数是248
使用补码的原因:
计算机中做求和运算时使用的加法器, 从真值表可以看到其本位和是异或的结果, 进位是与的结果
使用补码后, 本来要做减法的现在可以用补码的加法来计算
例如10-8=2
被转换为了10 + 2^8 + (-8) =2^8 + 2, 而补码运算对符号位运算产生的进位要舍弃, 也就相当于2^8 +2 - 2^8
上面是正常舍去进位的情况, 有时候是数值溢出了
例如8位二进制补码最多表示-128-127
如果两个127相加
结果254, 实际二进制是11111110 从符号位就可以看到这个数表示的是个负数
-2, Java在算术运算时如果数据溢出了不会抛异常或者Error, 而是会直接截断
怎么判断是正常舍入还是数值溢出呢?
可以通过java.lang.math里的addExact和subtractExtract来判断是否结果溢出, 如果溢出了会抛出异常
其原理是根据符号位的变化
十进制和二进制转换
对整数 除二取余 , 最后获得的余数放在最高位(左端)
对小数 乘二取整, 第一个获得的整数放在最靠近小数点位置
二进制与其它进制转换
每3位二进制对应一个八进制数字
每4位二进制对应一个十六进制数字
例如转换为16进制时, 对整数部分高位补0到长度是4的整数倍, 对小数部分低位补0到长度是4的整数倍, 然后直接转换
通过取反等操作获取整数的补码
原码: 符号位+数值部分 0为正 1为负
反码: 对正数, 反码与原码相同, 对负数, 反码是符号位之外的取反
补码: 对正数, 补码与原码相同, 对负数, 是反码+1
数值部分计算: 除2取余
8/2 = 4余0
4/2= 2余0
2/2 = 1余0
1/2 = 0余1
此时8的数值部分就是1000
假如按单字节存储的话, 那么原码反码补码列举如下
8的原码 0000 1000
8的反码 0000 1000
8的补码 0000 1000
-8的原码 1000 1000
-8的反码 1111 0111
-8的补码 1111 1000
负数的补码转换为原码, 按位取反+1
1000 0000
按位取反
1111 1111
+1
(进位1存不下被丢弃) 0000 0000
这种-0 规定为-128
当n为4byte也就是32bit时
8的补码0000 0000 0000 0000 0000 0000 0000 1000 (二进制表示)
也就是00 00 00 10(16进制表示)
-8的原码 10000000 00000000 00000000 00001000
-8的反码 11111111 11111111 11111111 11110111
-8的补码 11111111 11111111 11111111 11111000
补码的16进制为FF FF FF F8
验证:
int a=-8;
String str = Integer.toHexString(a);
System.out.println(str);//输出结果为fffffff8
float 4byte
浮点数在Java中以尾数形式存储
1bit(符号位) 8bits(指数位) 23bits(尾数位)
符号位表示 数值的正负
符号位+1.尾数*10^(尾数位-127) 为浮点数的真实值
十进制小数转换为尾数的计算方式
乘2取整
可以计算0.5的二进制表示
0.5 * 2 = 1.0 整数部分1
于是0.5的二进制
0.1
使用尾数表示法
1*2^-1
在java中隐含了这个1
因此0(符号位) -1+127(指数位) 000 0000 0000 0000 0000 0000(尾数位)
得到0 01111110 000 0000 0000 0000 0000 0000
也就是16进制
3F000000
验证代码:
float f = 0.5f;
int binary = Float.floatToIntBits(f);
System.out.println(Integer.toHexString(binary));//输出3f000000
但是也可能出现循环的情况
以0.2为例
0.2 * 2 = 0.4 整数部分0
0.4* 2 = 0.8 整数部分0
0.8*2 = 0.6 +1整数部分1
0.6*2 = 1.2 整数部分1
0.2*2= 0.4 整数部分0
发现出现了循环
于是0.0011 0011 001....
因此浮点数的0.2如果以尾数表示法直接存储时存储的不是准确值
此时使用尾数存储为
1.1 0011 001...........*2^(-3)
0(符号位) 127+(-3)(指数位) + 10011001100110011001100
0 01111100 10011001100110011001100 (1)
3E4CCCCC
代码验证:
float f1 = 0.2f;
int binary1 = Float.floatToIntBits(f1);
System.out.println(Integer.toHexString(binary1));//3e4ccccd 这是因为存储不下时发生了舍入
String hexString = "3E4CCCCC"; // 十六进制字符串
int intValue = Integer.parseInt(hexString, 16); // 将十六进制字符串转换为整数值
float floatValue = Float.intBitsToFloat(intValue); // 将整数值转换为float类型变量
System.out.println("Hex String: " + hexString);
System.out.println("Float Value: " + floatValue);
使用Jclasslib byteviewer查看常量池, 发现在编译时0.2就被存储为3e4ccccd
浮点型表示范围
从尾数表示法可以推出其表示的最大数位
0 255-127 111 1111 1111 1111 1111 1111
也就是
1.111 1111 1111 1111 1111 1111*2^128 约为3.403E38 ~ 3.403E38
浮点数精度极限为
推测
1.000 0000 0000 0000 0000 0000*2^-127
约为5.87747175411E-39
实际测试验证发现
String hexString = "00000001"; // 十六进制字符串
int intValue = Integer.parseInt(hexString, 16); // 将十六进制字符串转换为整数值
float floatValue = Float.intBitsToFloat(intValue); // 将整数值转换为float类型变量
System.out.println("Hex String: " + hexString);
System.out.println("Float Value: " + floatValue);
Hex String: 00000001
Float Value: 1.4E-45 约为2的-150次幂 怀疑是Java对齐做了优化 实际上2^-150约为1.576*10^-45次幂
精度和范围不能兼得
double 8byte
指数段有11位
尾数段有52位
1.798E308 ~ 1.798E308
自动类型转换
boolean 不能转换
byte short char 如果和整型常量做算术运算会自动提升为int
float和浮点型自动会提升为double 浮点常量若未用f标识默认是double型
int 和long可以自动转为float, 虽然可能会丢失精度, 但是编译机器不报警
float自动转为double不丢失精度
long number = 2147483647777777L;
float number1 = number;
System.out.println(number+"转换为了"+number1);//输出为2147483647777777转换为了2.14748365E15 可以看到数据精度丢失了
实际工作中对精度有要求的一般是使用Java.math.BigDicimal类