首先回顾一下二进制:
- 一个整数,按照
绝对值
大小转换成的二进制数叫做原码
- 将二进制数按位取反,叫做
反码
- 将
反码
+1,叫做补码
负数 是以它绝对值的二进制的 补码 形式存储的
例如一个字节的数据 -8,它的二进制数据是多少呢?
首先 -8 的绝对值为 8
8 的二进制数据为 100
一个字节也就是:00000100
反码为:11111011
+1 补码为:11111100
那么 -8 的二进制形式就为:11111100
基本数据类型
java 中有 八种基本数据类型
1 byte
字节类型
java 中 byte 字节类型大小为 8 个二进制位 0000 0000,并且因为其带有符号:正数或者负数,所以可以表示的大小为 -128 ~ 127
分析一下
byte n = 6;
6 的二进制数据为 110 ,那么在内存中 n 的存储形式为
0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 |
---|
其中,第一个二进制位的 0,表示这是一个正数还是负数,那么也就是说这八个二进制位能表示的最大正数为
0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
---|
01111111 转换为 10进制数是 127
而如果是一个负数的话,第一位就是 1,能表示的最小负数就是
1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
---|
读取时,发现第一位是 1,表明这是一个负数,那么就要按照读取负数的规则去读取数据
首先减去 1
0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
---|
按位取反
1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
---|
10000000 的十进制为 128
得到 10000000 表示的负数的十进制值为 -128
所以 8个带符号的二进制位能表示的数据范围为-128~127
不带符号的很好理解,就是 0~255
2 short
短整形
java 中 short 类型为两个字节大小,16个二进制位,通过第1步可知
short 类型能表示的数字范围为 -215~215 -1 -32768 ~ 32767
3 int
类型
java 中 int 类型为4个字节大小,32个二进制位
int 类型能表示的数字范围为 -2147483648 ~ 2147483647
4 long
类型
java 中 long 类型为8个字节大小,64个二进制位
long 类型能表示的数字范围为 -9223372036854775808 ~ 9223372036854775807
5 float
类型
java 中 long 类型为4个字节大小,32个二进制位
long 类型能表示的数字范围为 -2147483648 ~ 2147483647
6 double
类型
java 中 double 类型为8个字节大小,64个二进制位
double 类型能表示的数字范围为 -9223372036854775808 ~ 9223372036854775807
7 boolean
类型
boolean 只表示一位信息
只有两个值 true
false
默认值为 false
8 char
类型
java 中 char 类型为两个字节大小,16个二进制位,由于字符值没有正负之分,所以它的十进制等效值范围为0 ~ 65535
浮点数运算问题
值得注意的是,java 中的浮点数类型 float、double,进行运算时并不能准确的得到结果
小数的二进制转化规则分为了
小数点左边
与小数点右边
左边按照整数规则转换
右边的规则如下:将小数位拿出来 * 2,直到最后结果的小数位为 0 时结束
例如 0.12
0.12 * 2 = 0.24 … 0
0.24 * 2 = 0.48 … 0
0.48 * 2 = 0.96 … 0
0.96 * 2 = 1.92 … 1
0.92 * 2 = 1.84 … 1
0.84 * 2 = 1.68 … 1
…
会一直乘下去
所以最后 0.12 的二进制会变为
0.000111…
无限的数
而计算机在存储小数位时是有长度限制的,所以最后存储的是一个有误差的值
那么将它进行计算,肯定会导致误差
public static void main(String[] args) {
float f1 = 2.12f;
float f2 = 0.31f;
System.out.println(f1 + f2);
}
以上代码,按照十进制的运算规则,打印结果应该是 2.43,但是实际代码运行结果却是
2.4299998
编程语言都会有这种问题
为了解决浮点数之间运算的精度问题,例如,如何判断两个浮点数是否相等呢?一般是判断两个浮点数之差的绝对值是否小于一个很小的数
System.out.println( Math.abs(f1 - f2) < 0.00001);
另外 java 中提供了一个类 BigDecimal
,可以用来对超过十六位有效位的数进行精确的运算,上述代码中对 float 类型的数 f1 f2 相加得到的是一个有误差的结果,将它改成使用 BigDecimal 的形式
public static void main(String[] args) {
float f1 = 2.12f;
float f2 = 0.31f;
// System.out.println(f1 + f2); // 2.4299998
BigDecimal bd1 = new BigDecimal("2.12");
BigDecimal bd2 = new BigDecimal("0.31");
System.out.println(bd1.add(bd2));
}
这次得到的结果就是预期的 2.43
使用 BigDecimal 进行 加 减 乘 时,精度不会丢失,但是做除法的时候,会存在除不尽的情况,这个时候就要手动去指定保留的小数位
BigDecimal d1 = new BigDecimal("123.456");
BigDecimal d2 = new BigDecimal("23.456789");
BigDecimal d3 = d1.divide(d2, 10, RoundingMode.HALF_UP); // 保留10位小数并四舍五入
BigDecimal d4 = d1.divide(d2); // 报错:ArithmeticException,因为除不尽
BigDecimal 类提供了很多常用的计算方法,例如保留小数位,取商和余数等
评论区