cyn's blog cyn's blog
首页
  • java开发知识
  • 开发问题记录
  • 计算机网络
  • 数据结构与算法
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 学习
  • 面试
  • 实用技巧
个人简历
GitHub (opens new window)
首页
  • java开发知识
  • 开发问题记录
  • 计算机网络
  • 数据结构与算法
  • 技术文档
  • GitHub技巧
  • Nodejs
  • 博客搭建
  • 学习
  • 面试
  • 实用技巧
个人简历
GitHub (opens new window)
  • java技术

    • Java 快读快输出
    • 自定义比较器
    • session和token有什么区别?
    • HashMap为什么比数组查询快
    • int和Integer区别详解
    • String和StringBuffer
    • 接口和抽象类区别
    • 小数计算都是不精确的
      • 3*0.1 == 0.3 将会返回什么?true 还是 false?
      • 为什么会出错呢?
      • 为什么一定要用二进制呢?
      • 为什么有的小数计算是准确的?
      • 怎么处理计算不精确
      • 小结
    • 判断数组、字符串、集合为空和null
    • 布隆过滤器
    • Java实体类实现Serializable接口?(序列化)
    • java.util.Arrays.asList()
    • URI_URL
    • volatile和synchronized的区别
    • Nginx+Tomcat实现负载均衡、动静分离集群
    • nginx常用命令
  • 开发问题记录

    • 关闭端口号占用的进程
    • 前后端跨域问题
    • java调用外部程序Runtime.getRuntime().exec
    • 静态资源映射,访问、上传到服务器本地
  • java开发
  • java技术
cyn
2023-05-26
目录

小数计算都是不精确的

# 3*0.1 == 0.3 将会返回什么?true 还是 false?

false,因为有些浮点数不能完全精确的表示出来。因此,判断要用-,小于如1e-5则相等。 再比如:

float f = 0.1f*0.1f;
System.out.println(f);//0.010000001
1
2

# 为什么会出错呢?

实际上,不是运算本身会出错,而是计算机根本就不能精确的表示很多数,比如0.1这个数。 计算机是用一种二进制格式存储小数的,这个二进制格式不能精确表示0.1,它只能表示一个非常接近0.1但又不等于0.1的一个数。 数字都不能精确表示,在不精确数字上的运算结果不精确也就不足为奇了。 0.1怎么会不能精确表示呢?在十进制的世界里是可以的,但在二进制的世界里不行。在说二进制之前,我们先来看下熟悉的十进制。 实际上,十进制也只能表示那些可以表述为10的多少次方和的数,比如12.345,实际上表示的:1_10+2_1+3_0.1+4_0.01+5*0.001,与整数的表示类似,小数点后面的每个位置也都有一个位权,从左到右,依次为 0.1,0.01,0.001,…即10^(-1), 10^(-2), 10^(-3)。 很多数,十进制也是不能精确表示的,比如1/3, 保留三位小数的话,十进制表示是0.333,但无论后面保留多少位小数,都是不精确的,用0.333进行运算,比如乘以3,期望结果是1,但实际上却是0.999。 二进制是类似的,但二进制只能表示哪些可以表述为2的多少次方和的数,来看下2的次方的一些例子:

2的次方 十进制
2^(-1) 0.5
2^(-2) 0.25
2^(-3) 0.125
2^(-4) 0.0625

因此只可以精确表示为2的某次方之和的数,其他数则不能精确表示。

# 为什么一定要用二进制呢?

为什么就不能用我们熟悉的十进制呢?在最最底层,计算机使用的电子元器件只能表示两个状态,通常是低压和高压,对应0和1,使用二进制容易基于这些电子器件构建硬件设备和进行运算。如果非要使用十进制,则这些硬件就会复杂很多,并且效率低下。

# 为什么有的小数计算是准确的?

如果你编写程序进行试验,你会发现有的计算结果是准确的。比如,我用Java写:

System.out.println(0.1f + 0.1f);//0.2
System.out.println(0.1f * 0.1f);//0.010000001
1
2

按照上面的说法,第一行的结果应该也不对啊? 其实,这只是Java语言给我们造成的假象,计算结果其实也是不精确的,但是由于结果和0.2足够接近,在输出的时候,Java选择了输出0.2这个看上去非常精简的数字,而不是一个中间有很多0的小数。

# 怎么处理计算不精确

计算不精确,怎么办呢?

  • 减小精度。大部分情况下,我们不需要那么高的精度,可以四舍五入,或者在输出的时候只保留固定个数的小数位。
  • 进行转换。如果真的需要比较高的精度,可以将小数转化为整数进行运算,运算结束后再转化为小数。
  • 使用十进制的数据类型。这个没有统一的规范,在Java中是用BigDecimal,运算更准确,但效率比较低。

# 小结

很多小数计算机中不能精确表示,通常只可以精确表示为2的某次方之和的数,其他数则不能精确表示,因为计算机的基本思维是二进制的。

编辑 (opens new window)
上次更新: 2023/05/26, 15:58:27
接口和抽象类区别
判断数组、字符串、集合为空和null

← 接口和抽象类区别 判断数组、字符串、集合为空和null→

Theme by Vdoing | Copyright © 2023-2023 cyn | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式