多的是,你不知道的“浮点数”
很多人的疑问是程序的运行结果是9,不应该是8吗?我们可以在程序中运行这样一句代码
System.out.println( 0.1 + 0.7 );
|
程序运行的结果是0.7999999999999999。 这个数明显是小于0.8的,所以就有了上图的运行结果。那么为什么会出现这种现象呢?
问题原理
其实计算机中很多浮点数本身就是近似值,因为他们不能被精确的表示。这源于计算机的底层是二进制的,比如0.1 。0.1为什么不能精确的表示呢?在十进制的世界里时可以精确表示的,但是在二进制中则不行。下面我们举个例子。比如78.912,是这样表示的。7*10+8*1+9*0.1+1*0.01+2*0.001,小数的每一位也有位权,切换为科学计数法,则是7*10^1+8*10^0+9*10^(-1)+1*10^(-2)+2*10^(-3)。 虽然很多数在10进制里可以精确表示,但是也有很多数在二进制里面依然不能精确表示,比如10/3 近似为3.33 无论多少位小数,也不能精确表示10/3, 只能是近似为3.33。 其实二进制也是类似的,二进制的小数用科学计数法来表示的话,先来看看2的某某次方对应的10进制数据吧。 所以我们就能理解了 十进制的0.1 = 1*2^(-?)+1*2^(-?)+1*2^(-?)+…. ,无论怎么相加,最后也只能无限接近于0.1 ,而不是真正的0.1 。 那有人会问,程序中确实显示的是0.1,这只是Java语言给我们造成的假象,计算结果其实也是不精确的,但是由于结果和0.1足够接近,在输出的时候,Java选择了输出0.1这个看上去非常精简的数字,而不是一个中间有很多0的小数。在误差足够小的时候,结果看上去是精确的,但不精确其实才是常态。 二进制中表示小数,也采用科学计算方法,形如m*(2^e)。 m称为尾数,e称为指数。指数可以为正,也可为负,计算机中的浮点数单独表示尾部分和指数部分,外加一个符号位。几乎所有的硬件和语言表示的小数的二进制格式都是一样的,这是一种标准,叫做IEEE754标准,他定义了两种格式,一种是32位的,对应于Java的float,另一种是64位的,对应于Java的double,32位格式中,1位表示符号,23位表示尾数,8位表示指数。64位格式中,1位表示符号,52位表示尾数,11位表示指数。IEEE754中还有一些复杂的细节,难以理解,而且不常用,所以本文暂时先不介绍了。 也有人会问,为什么计算机底层的数据为什么非要用二进制去表示呢?计算机无非是一个电器,里面有无数的电阻和电容,当计算机通交流电之后,遇到电容是低电压用0表示,遇到电阻是高电压用1表示,所以计算机的底层只能是二进制,因为他只能表示高低电压。这是模拟电路和数字电路的知识。
问题解决方案
方案1: 使用浮点数计算的时候,我们可以把小数变成int或者是long,计算完毕后可以还原float或者double类型,举个例子:比如计算0.1-0.9的和,可以如下图这样计算。
1
2
3
4
5
6
|
//求1-9的和 最后结果再除以10
int sum = 0 ;
for ( int i = 1 ; i <= 9 ; i++) {
sum+=i;
}
System.out.println(sum/ 10.0 ); //4.5
|
方案2: 使用java.math.BigDecimal这个类来运算。 比如0.1+0.7,请看下列代码。
01
02
03
04
05
06
07
08
09
10
|
package cam.itheima.demo;
import java.math.BigDecimal;
public class Demo5 {
public static void main(String[] args) {
BigDecimal bd1 = new BigDecimal( "0.1" );
BigDecimal bd2 = new BigDecimal( "0.7" );
BigDecimal sum = bd1.add(bd2);
System.out.println(sum);
}
}
|
这两种方案各有利弊,方案一速度快不消耗太多的内存,但是如果数据过大,int和long类型表示不了。方案二可以表示很大的数据,但是速度比较慢内存消耗比较大。总结: 本文讲述了Java中的浮点数不精确的现象,并讲述了计算机底层表示浮点数的原理从而解释了浮点数不精确的原因,最后提出了浮点数参与精确运算的解决方案。
多的是,你不知道的“浮点数”相关推荐
- java泛型一定用包装类_你不知道的基本数据类型和包装类
你不知道的基本数据类型和包装类 基本数据类型 Java 基本数据按类型可以分为四大类:布尔型.整数型.浮点型.字符型,这四大类包含 8 种基本数据类型.布尔型:boolean 整数型:byte.sho ...
- php formdata 多个图片保存_图片上传姿势以及你不知道的Typed Arrays
在思否答题遇到几个关于图片上传的问题,中间都涉及到ArrayBuffer的概念,心心念念想整理下这方面的知识,也希望让更多人能有所收获. 各位看官,一起开始吧. 1. 如何上传文件 前端中上传一般使用 ...
- 你不知道的三大 JavaScript “黑话”!
作者 | 斯年 责编 | 伍杏玲 因为球是圆的,所以不论发生什么都有可能,对这点我是深信不疑的,但最近我总是在怀疑,JavaScript也是圆的!下面我们一起来看看JavaScript有啥黑话: &q ...
- 你不知道的JavaScript--Item5 全局变量
1.尽量少用全局对象 全局变量的问题在于,你的JavaScript应用程序和web页面上的所有代码都共享了这些全局变量,他们住在同一个全局命名空间,所以当程序的两个不同部分定义同名但不同作用的全局变量 ...
- 你不知道的JavaScript--Item10 闭包(closure)
JavaScript 闭包究竟是什么? 用JavaScript一年多了,闭包总是让人二丈和尚摸不着头脑.陆陆续续接触了一些闭包的知识,也犯过几次因为不理解闭包导致的错误,一年多了资料也看了一些,但还是 ...
- python 浮点数未解之谜
疑问: print(8.1+0.03)ouput: 8.129999999999999 print(0.1+0.1+0.1-0.3)output: 5.551115123125783e-17 结论 多 ...
- C语言中将0到1000的浮点数用强制指针类型转换的方式生成一幅图像
搞过计算机图像的人都知道,图像中的每一个像素通常为一个整型数,它可以分成4个无符号的char类型,以表示其RGBA四个分量.一幅图像可以看做是一个二维整型数组.这里我会生成一个float数组,其数组大 ...
- IEEE-754标准(32位) 十六进制转换十进制浮点数
因实验需要,读取陀螺仪的数据是16进制的数据,需要将该数据转化为10进制方便自己查看,理解.记录如下: 1.将(32位)16进制IEEE-754标准浮点数就是用十六进制表示浮点,称为单精度浮点数. f ...
- JS加法函数,用来得到精确的加法结果(说明:javascript的加法结果会有误差,在两个浮点数相加的时候会比较明显。这个函数返回较为精确的加法结果)
//加法函数,用来得到精确的加法结果 //说明:javascript的加法结果会有误差,在两个浮点数相加的时候会比较明显.这个函数返回较为精确的加法结果. //调用:accAdd(arg1,arg2) ...
最新文章
- [深度学习] keras的EarlyStopping使用与技巧
- pandas isnull 函数
- 交通预测论文笔记:Spatio-Temporal Graph Convolutional Networks: A Deep Learning Frameworkfor Traffic Forecast
- S5PV210开发 -- I2C 你知道多少?(二)
- python语言程序设计实践教程答案实验六_20192417 实验一《Python程序设计》实验报告...
- 深入理解include预编译原理
- sql查询慢原因及优化
- 2018 考研 408 经验贴——总结篇
- sqlplus方向键问题_wuli大世界_新浪博客
- Capstone CS5218转接设计|DP转HDMI 4K 30HZ转接电路
- 大数据可视化陈为智慧树_知到智慧树大数据可视化网课答案
- Python网络爬虫:爬取腾讯招聘网职位信息 并做成简单可视化图表
- 那些让我印象深刻的五个bug
- 别人可以在今日头条发文章赚钱,为什么你赚不到呢?
- word给代码加行号
- Linux无法显示ip的解决办法
- c语言基础知识题目,C语言基础知识复习题
- Android 学习笔记之九 下拉刷新
- H.264——使用H.264视频编解码器JM进行YUV图像序列的编解码
- siesta在Linux运行,并行编译SIESTA