二进制运算误差问题

我们知道在处理一些浮点数的时候,运算会产生误差,得到的是类似无限循环。

例子:

  

    @Test
    public void Demo(){
        double a1=2.0;
        double a2=1.1;
        System.out.println(a2-a1);//-0.8999999999999999
    }

其原因是计算机所使用二进制01代码无法准确表示某些带小数位的十进制数据。

下面我们来分析下:
我们知道将一个十进制数值转换为二进制数值,需要通过下面的计算方法:
1. 整数部分:连续用该整数除以2,取余数,然后商再除以2,直到商等于0为止。然后把得到的各个余数按相反的顺序排列。简称"除2取余法"。
2. 小数部分:十进制小数转换为二进制小数,采用"乘2取整,顺序排列"法。用2乘以十进制小数,将得到的整数部分取出,再用2乘余下的小数部分,然后再将积的整数部分取出,如此进行,直到积中的小数部分为0或者达到所要求的精度为止。然后把取出的整数部分按顺序排列起来,即先取出的整数部分作为二进制小数的高位,后取出的整数部分作为低位有效位。简称"乘2取整法"。
3. 含有小数的十进制数转换成二进制,整数、小数部分分别进行转换,然后相加。

例如:将十进制数值25.75转换为二进制数值,步骤如下:

25(整数部分)
25/2=12......1
12/2=6.......0
6/2=3......0
3/2=1......1
1/2=0......1
(25) 10=(11001) 2

0.75(小数部分)
0.75*2=1.5......1
0.5*2=1......1
(0.75) 10=(0.11) 2
(25.75) 10=(11001) 2+(0.11) 2=(11001.11) 2

按照上述方法,我们将0.65及0.6转换为二进制代码:
(0.65)10 = (0.101001100110011001100110011001100110011......)2
(0.6) 10 = (0.10011001100110011001100110011001100110011......)2

后面的省略号表示已经算不完了,后面在无限重复 0011 这段二进制数值。

如何解决这个问题?知道其根本原因后,我们知道是无法从根本上解决这个问题的,但我们可以有一些曲线救国的方法,下面列举几个:
1. 因为二进制数值可以准确表示整数(可以使用整数转换为二进制方法验证下),所以可以将小数乘以10或100等变成整数,然后做整数运算,最后再通过除以10或100等获得结果;
2. 通过截取结果的有效小数位数等,来取得最好的近似结果,然后在做处理。
3. 对于可以用有限长度的二进制数值表示的十进制数值,可以使用存储位数大于其长度的数据类型。

java中提供了BigDecimal这个超大的类,用来存储浮点型,使用它可以处理二进制误差问题。

@Test
    public void Demo1(){
        BigDecimal b1=new BigDecimal(2.0+"");//注意:只能使用String类型的构造
        System.out.println(b1.subtract(new BigDecimal(1.1+"")));//0.9
    }

其他具体方法查看api。大的整形数据使用BigDecimal

时间: 2024-10-05 05:29:07

二进制运算误差问题的相关文章

web day25 web day24 小项目练习图书商城, 购物车模块,订单模块,支付(易宝支付)

购物车模块 购物车存储: 保存在session中(本次使用的) 保存在cookie中 保存在数据库中 购物车相关类 购物车结构 CartItem:包含图书和数量,小计 Cart:包含一个Map<String,CartItem>和部分购物车操作方法 修改登录方法,在用户登录成功后,马上在session中添加一辆车 页面负责遍历存在session域中的购物车属性 添加购物车条目 清空购物车条目 指定删除购物车条目 图 我的购物车 top.jsp中存在一个链接:我的购物车 我的购物车直接访问/jsp

iOS: 零误差或极小误差的定时执行或延迟执行?

问题如下: 节奏类游戏需要执行很多的跟音乐节拍相关的操作,并且为了保证节奏感,需要让操作跟节拍的关系十分紧密.对两者间隔要求不能超过0.02秒或更低. 目前使用了 GCD 中的 asyncAfter(deadline:)方法,不过误差总是要大于0.05秒,并且还无法保证误差会不会传递下去.请问有更好的方式来解决误差吗? var time = Date().timeIntervalSince1970 let dq = DispatchQueue(label: "queue", qos:

SICP 习题 (2.15)解题总结:区间误差的深入思考

SICP 习题 2.15 是接着 题目 2.14 的, 题目 2.14中提到了Alyssa设计的区间计算模块在并联电阻计算时会出现问题,这个问题是Lem发现的.接着,一个叫Eva的人也发现了这个问题,同时她还有更深入的思考. Eva觉得,如果一个公式可以写成一种形式,其中具有非准确性的变量不重复出现,那么Alyssa的系统产生的区间的限界会更紧一些. 因此,她觉得在计算并联电阻时,公式"1/(1/R1 + 1/R2)"比公式"(R1*R2)/ (R1 + R2)"要

加州理工学院公开课:机器学习与数据挖掘_误差和噪声(第四课)

这一课的主题是:误差分析与噪声处理. 该课时的主要内容如下: 1.Nonlinear Transformation(Continue)(非线性转换(续)) 2.Error Measure (误差度量)(重点) 3.Noisy Targets(噪声指标)(重点) 4.Preamble to the Theory(理论热身) 1.Nonlinear Transformation: 在上一节课的最后,作者举了一个关于非线性转换的例子.通过该例子我们可以直观的看到非线性的数据可以被转化成线性的数据并且利

误差输入点和原始信号输入点之间的通路增益对系统的影响 自动控制原理

误差输入点和原始信号输入点之间的通路增益对系统的影响 当R作用时,N=0; 系统是常见的二阶单位反馈系统 在阶跃信号作用下 闭环传递函数当s->0时 ess = s->0          s*E(s) = s*(R(s)-C(s)) 于是稳态误差ess = 0 当N作用时,R =0; 系统是常见的二阶单位反馈系统,反馈增益H(s) = K1 为常数 在误差为阶跃信号作用下 enss = s->    s*(误差传递函数(s)) = s*(K2/(T*s^2+s+K1*K2))*(R(s

【转】GPS误差来源

一.与GPS卫星有关的误差 1.卫星时钟误差 即使卫星是非常的精密复杂,它可以计算出一些极微小的讯息信息,如原子钟(Cesium) 即是如此一个精准的装置,但是精准并不代表完美,因此仍会有一些微小的误差产生,即使卫星的定位会持续的被监控着,但并不是每一秒都处于被监视的状态之中,这期间一旦有微小的定位误差或卫星星历的误差产生,便会影响到接受器在定位计算时的准确性. 2.星历误差(即卫星轨道误差) 卫星星历误差 在进行GPS定位时,计算在某时刻GPS卫星位置所需的卫星轨道参数是通过各种类型的星历提供

(转载)高速ADC的关键指标:量化误差、offset/gain error、DNL、INL、ENOB、分辨率、RMS、SFDR、THD、SINAD、dBFS、TWO-TONE IMD

(一)一个基本概念 分贝(dB):按照对数定义的一个幅度单位.对于电压值,dB以20log(VA/VB)给出:对于功率值,以10log(PA/PB)给出.dBc是相对于一个载波信号的dB值:dBm是相对于1mW的dB值.对于dBm而言,规格中的负载电阻必须是已知的(如:1mW提供给50Ω),以确定等效的电压或电流值. (二)静态指标定义 1.量化误差(Quantization Error) 量化误差是基本误差,用简单3bit ADC来说明.输入电压被数字化,以8个离散电平来划分,分别由代码000

UVA 10200 记忆打表,素数筛,浮点误差

UVA 10200 区间预处理,浮点误差 W - Prime Time Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Submit Status Practice UVA 10200 Description 题意:测试找素数函数f(n)=n^2+n+41在区间n<-[a,b]时,找到素数的成功率. 思路:区间的素数个数,打表预处理即可.输出答案时四舍五入,需注意浮点误差,四舍五入时加上EPS. #

小数在计算机中为什么会有误差?说明机器数、码制、浮点数、以及数制转换的一些问题

1.常用的数制 十进制  0~9 八进制 0~7 二进制 0~1 十六进制 0~F 2.十进制 转 各个进制 方法 : 除以基数取余反向 3. 2进制  8进制  16进制 转十进制 二进制 ___________________________ 2^3     2^2    2^1     2^0 1         0          0         1         X =8+ 1 = 9 八进制 ———————————-------------- 8^1    8^0 1