侧边栏壁纸
  • 累计撰写 10 篇文章
  • 累计创建 5 个标签
  • 累计收到 2 条评论
标签搜索

目 录CONTENT

文章目录

浮点数运算问题

首先回顾一下二进制:

  • 一个整数,按照绝对值大小转换成的二进制数叫做 原码
  • 将二进制数按位取反,叫做反码
  • 反码 +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 类提供了很多常用的计算方法,例如保留小数位,取商和余数等

2

评论区