计算机之所以叫"计算"机就是因为发明它主要是用来计算的,"计算"当然是它的特长,在大家的印象中,计算一定是非常准确的。但实际上,即使在一些非常基本的小数运算中,计算的结果也是不精确的。

比如:

float f = 0.1f*0.1f;
System.out.println(f);
1
2
这个结果看上去,不言而喻,应该是0.01,但实际上,屏幕输出却是0.010000001,后面多了个1。

看上去这么简单的运算,计算机怎么会出错了呢?

为什么会出错呢?
实际上,不是运算本身会出错,而是计算机根本就不能精确的表示很多数,比如0.1这个数。

计算机是用一种二进制格式存储小数的,这个二进制格式不能精确表示0.1,它只能表示一个非常接近0.1但又不等于0.1的一个数。

数字都不能精确表示,在不精确数字上的运算结果不精确也就不足为奇了。

0.1怎么会不能精确表示呢?在十进制的世界里是可以的,但在二进制的世界里不行。在说二进制之前,我们先来看下熟悉的十进制。

实际上,十进制也只能表示那些可以表述为10的多少次方和的数,比如12.345,实际上表示的:110+21+30.1+40.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);
System.out.println(0.1f * 0.1f);
1
2
第一行输出0.2,第二行输出0.010000001。按照上面的说法,第一行的结果应该也不对啊?

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

在误差足够小的时候,结果看上去是精确的,但不精确才是常态。

怎么处理计算不精确
计算不精确,怎么办呢?

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

理由就是:很多小数计算机中不能精确表示,通常只可以精确表示为2的某次方之和的数,其他数则不能精确表示。计算机的基本思维是二进制的,所以,意料之外,情理之中吧。

JAVA中小数为什么不精确相关推荐

  1. java中小数的处理:高精度运算用bigDecimal类,精度保留方法,即舍入方式的指定

    java中小数的处理:高精度运算用bigDecimal类,精度保留方法,即舍入方式的指定 2016年05月11日 11:20:08 阅读数:6336 一. 计算机的小数计算一定范围内精确,超过范围只能 ...

  2. java怎么进行浮点数运算_【考试经验】Java中实现浮点数的精确运算

    [考试经验]Java中实现浮点数的精确运算 package com.lv; import java.math.BigDecimal; public class Arith { public stati ...

  3. java小数的数据类型_【填空题】Java 中小数默认的数据类型为 ,如果要指定为 类型,要在小数后面加F或f。...

    [填空题]Java 中小数默认的数据类型为 ,如果要指定为 类型,要在小数后面加F或f. 更多相关问题 - Your plan is perfect and I believe that it wil ...

  4. java中小数后加f_在 Java 中,小数默认为 ,如果要指定 类型请在小数后加 F/f 。_学小易找答案...

    [填空题]Java 语言采用双字节的 编码. [单选题]马斯洛需要层次论所提出的5种需要:生理需要.安全需要.归属需要.( ).自我实现需要 [填空题]String s= " abc &qu ...

  5. Java中小数默认为double类型

    A:5.3e12表示5.3乘以10的12次方,正确 B:在Java中,如果你输入一个小数,系统默认的是double类型的,这个式子相当于 float f=double 11.1,明显错误,如果想要表达 ...

  6. java中小数类型_java中小数属于什么类型的数据

    展开全部 小数属于浮点型(默认为double). 浮点型代表的是实数,其实就是包含小数的部分.也知道现实世界中是由32313133353236313431303231363533e59b9ee7ad9 ...

  7. java中小数的乘法_javascript的小数点乘法除法实例

    javascript的小数点乘法除法实例 导语:想要学好Java语言,必不可少的就是它的四则运算,特别是乘除法.下面的是百分网小编为大家搜集的javascript的小数点乘法除法实例,希望可以帮到你. ...

  8. java怎么进行浮点数运算_怎样在Java中实现浮点数的精确运算?

    package com.lv; import java.math.BigDecimal; public class Arith { public static double add(double v1 ...

  9. Java中使用Rational类实现分数精确的计算,

    Java中使用Rational类实现分数精确的计算, 在Java中实现分数的精确计算(Rational类) 在Java中想要进行有分数精确的计算,例如1/3=0.33333333-,这个数字不能用do ...

最新文章

  1. php 提交的数据覆盖,如何高效的做数据覆盖操作
  2. R语言vtreat包自动处理dataframe的缺失值并生成对应的数据列_isbad来指示数据的原始缺失情况、查看特定字段缺失的那些数据行、查看数据集中多个字段的均值
  3. jzoj1751-Span(每日C组)【并查集,贪心】
  4. myeclipse连接mysql怎么调用_myeclipse连接mysql数据库详细步骤
  5. android 键盘点击事件监听事件,Android 键盘事件触发以及监听
  6. 不小心执行了 rm -rf,除了跑路还有其他办法吗?
  7. SAR图像变化检测的评价方法
  8. OpenStack 的Nova组件详解
  9. [渝粤教育] 武汉理工大学 复变函数与积分变换 参考 资料
  10. ArcGIS与地理加权回归GWR【一】
  11. 精美男女装、韩版、日系证件照素材合集,P个美美的证件照,不再烦恼
  12. ACCESS-入门思维导图
  13. RecyclerView的canScrollVertically方法踩坑
  14. Python金融系列第五篇:多元线性回归和残差分析
  15. CC00230.CloudKubernetes——|KuberNetes细粒度权限控制.V14|——|Ratel.v02|k8s资源管理平台配置|
  16. 盘点MES系统物料管理那些事儿
  17. 无代码白话版通俗的理解机器学习如何对未知的数据进行预测
  18. 传统的财务分析方法及手段总结
  19. HGVS制订的变异位点命名规则
  20. [转]情侣相处最佳模式

热门文章

  1. 笑话(18) 当吸烟学生遭遇班主任
  2. 【小程序】获取快递100物流信息
  3. 都2023年了,Android凉了没?
  4. mysql-下载安装
  5. 文件共享服务器如何提高网速,怎么提高网速 提高网速方法【详细介绍】
  6. 科创板|柏楚电子股价首次跌破200元
  7. 利用turtle绘制五角星
  8. TCP利用封包和解包解决“粘包”问题
  9. Mongo数据库操作(五)
  10. Windows平台下快速搭建Emacs