浮点数运算不准确怎么办?

引言

21世纪了,计算机怎么还算不准浮点数?我xx都能秒算出…乱入了乱入了。
Chrome控制台直接运算
上图为Chrome控制台直接运算结果

浮点数简介

浮点数是一种用于表示实数的计算机编码系统,它可以表示非常大或非常小的数值。它基于科学计数法,将一个数表示为尾数和指数的乘积。在计算机中,浮点数使用二进制科学计数法表示。由于计算机的存储空间有限,浮点数只能近似地表示实数,因此在进行浮点数运算时,可能会出现精度问题。

浮点数精度问题概述

在描述这个问题之前,我们不妨想一下这个数学问题?1/3*3 = 1,而0.333…*3 = 1?

浮点数精度问题主要源于计算机使用有限的位数来表示实数。由于这种限制,许多实数在计算机中只能被近似表示,这就可能导致精度损失。例如,1/3在十进制中是一个无限循环小数,无法精确表示。在二进制中,类似的问题也存在,例如0.1无法被精确表示。当我们进行浮点数运算时,这种近似误差可能会累积,导致最终结果的精度损失。例如,如果我们将0.1加10^6次,理论上的结果应该是100000.0,但实际的计算结果可能会有所偏差。此外,浮点数的比较也可能出现问题。例如,如果我们比较两个非常接近的浮点数,由于精度问题,它们可能被错误地认为是相等的。因此,理解浮点数精度问题对于编程和科学计算非常重要。我们需要了解这个问题的原因,并学会如何避免或减小精度损失。

在这里插入图片描述
上图为计算机0.1二进制转换过程

面向初学者的解释

什么是浮点数?

1.浮点数的定义:浮点数是一种用于表示实数的计算机编码系统,它可以表示非常大或非常小的数值。与整数相比,浮点数可以表示小数部分,因此具有更广泛的应用范围。
2.浮点数的表示方法:浮点数基于科学计数法,将一个数表示为尾数和指数的乘积。在计算机中,浮点数使用二进制科学计数法表示。一个浮点数通常由符号位、指数位和尾数位组成。
3.浮点数的标准:IEEE 754是一种广泛使用的浮点数表示标准,它定义了单精度(32位)和双精度(64位)浮点数的表示方法和运算规则。
4.浮点数与整数的区别:整数是没有小数部分的数,而浮点数可以表示小数部分。整数在计算机中的表示方法通常更简单,而浮点数的表示和运算更复杂。此外,浮点数可能会出现精度问题,而整数运算通常是精确的(有位数过大溢出问题)。

浮点数精度问题是什么?

1.浮点数精度问题的本质:由于计算机内存的限制,浮点数在计算机中的表示是有限的。这意味着许多实数只能被近似表示,而这种近似可能导致精度损失。例如,0.1在二进制中是一个无限循环小数,无法精确表示。
2.精度损失的影响:当我们进行浮点数运算时,这种近似误差可能会累积,导致最终结果的精度损失。这在科学计算、金融计算等需要高精度的领域可能会导致严重的问题。
3.浮点数比较的问题:由于精度问题,比较两个浮点数是否相等可能会出现问题。例如,如果我们比较两个非常接近的浮点数,由于精度问题,它们可能被错误地认为是相等的。
4.如何处理浮点数精度问题:虽然浮点数精度问题无法完全避免,但我们可以采取一些策略来减小其影响,例如使用更高精度的浮点数类型,或者在比较浮点数时使用一定的容差。

面向专业技术人士的深入讨论

浮点数的内部表示

1.浮点数的组成:一个浮点数通常由三部分组成:符号位、指数位和尾数位。符号位决定了浮点数的正负,指数位和尾数位则决定了浮点数的大小和精度。
2.IEEE 754标准:这是一种广泛使用的浮点数表示标准。在这个标准中,单精度浮点数由1位符号位、8位指数位和23位尾数位组成,而双精度浮点数由1位符号位、11位指数位和52位尾数位组成。
在这里插入图片描述
上图为单精度浮点数的真值表示

3.浮点数的表示方法:浮点数的表示基于科学计数法。在二进制科学计数法中,一个浮点数被表示为1.xxxx * 2^n的形式,其中1.xxxx是尾数,n是指数。尾数的第一位通常是1,因此在IEEE 754标准中,这一位通常被省略。
4.特殊的浮点数值:IEEE 754标准定义了一些特殊的浮点数值,如正无穷、负无穷和NaN(非数字)。这些值在处理溢出、下溢和未定义操作时非常有用。

精度问题的根源

1.有限的表示能力:计算机内存有限,因此浮点数的表示也是有限的。这意味着许多实数在计算机中只能被近似表示。例如,某些有限的十进制小数(如0.1)在二进制中是无限循环小数,因此无法精确表示。
2.舍入误差:当我们将一个无法精确表示的实数转换为浮点数时,需要进行舍入。这种舍入可能导致误差,称为舍入误差。舍入误差是浮点数精度问题的一个重要原因。
3.累积误差:在进行浮点数运算时,舍入误差可能会累积。例如,当我们对一系列浮点数进行加法或乘法运算时,每次运算都可能引入新的舍入误差,导致最终结果的误差增大。
4.误差放大:在某些情况下,浮点数运算可能导致误差放大。例如,在求解病态线性系统时,由于条件数很大,误差可能被放大,导致求解结果不准确。

如何处理浮点数精度问题

使用更高精度的浮点数类型:许多编程语言提供了不同精度的浮点数类型,如单精度(float)和双精度(double)。在需要高精度计算的场景中,可以选择使用更高精度的浮点数类型。
使用定点数或高精度数值库:在某些应用中,如金融计算,可以使用定点数或高精度数值库(如Java的BigDecimal,Python的decimal模块)来避免浮点数精度问题。
在比较浮点数时使用容差:由于精度问题,直接比较两个浮点数是否相等可能会出现问题。可以使用容差(如绝对误差或相对误差)来进行比较,以避免误差。

以下是各种高级编程语言处理浮点数精度问题的方法:
Java:可以使用BigDecimal类来进行高精度计算。BigDecimal类提供了丰富的数学运算方法,可以避免浮点数精度问题。
Python:可以使用decimal模块中的Decimal类来进行高精度计算。Decimal类提供了丰富的数学运算方法,可以避免浮点数精度问题。
Go:可以使用math/big包中的Rat(有理数)或Float(任意精度浮点数)类型来进行高精度计算。这些类型提供了丰富的数学运算方法,可以避免浮点数精度问题。
PHP:可以使用bcmath扩展或GMP扩展来进行高精度计算。这些扩展提供了丰富的数学运算方法,可以避免浮点数精度问题。
JavaScript:可以使用第三方库,如decimal.js或big.js,来进行高精度计算。这些库提供了丰富的数学运算方法,可以避免浮点数精度问题。

浮点数精度处理底层逻辑

常见的处理方法是有理数算法、查找表法、原生支持法
有理数算法:所有的数字都被表示为两个整数的比值,即一个分子和一个分母。这样,所有的计算都可以在有理数范围内进行,从而避免了由于浮点数的精度问题带来的误差。通俗理解,将小数转换为整数,记录小数位的位置即可。然后通过整数运算,因为整数运算是准确的,最终在通过小数位移位四舍五入即可。使用Java的BigDecimal类进行举例,每个BigDecimal对象都包含两个整数的数组,一个用于存储该对象的值(unscaled value),另一个用于存储该对象的标度(scale)。其中,unscaled value是一个长整型数组,用于存储该对象的绝对值,而scale是一个整数,用于存储该对象的小数点位置。在进行算术运算时,BigDecimal对象会先将unscaled value和scale进行相应的运算,然后再根据需要调整scale的值,以得到精确的结果。比如0.1加0.25。0.1它被表示为1乘以10^-1,其中1是unscaled value,-1是scale的值。0.25,它被表示为25乘以10^-2,其中25是unscaled value,-2是scale的值。通过scale和unscaled value算出35在通过scale-2,最终得出0.35。通过这种算法就可以得出精准的浮点数运算值,但是和普通的加减法相比会损耗一些性能。
在这里插入图片描述
上图为0.1+0.25计算过程

查找法:先把一些运算的值存储出来,在进行运算时,通过key查询出来。本质上就是通过存储换时间。

原生支持法:一些语言和平台原生支持高精度浮点数运算,可以直接使用内置的高精度计算功能。高级语言直接调用这些功能

结论

为什么我们需要理解浮点数精度问题

1.避免误解和错误:浮点数精度问题可能导致计算结果出现误差,甚至导致程序错误。理解这些问题可以帮助我们避免这些问题,编写出更准确、更可靠的程序。
2.提高计算精度:理解浮点数精度问题可以帮助我们选择更合适的数值类型和计算方法,提高计算结果的精度。例如,我们可以选择使用更高精度的浮点数类型,或者使用高精度数值库。
3.提高程序性能:在某些情况下,理解浮点数精度问题可以帮助我们提高程序性能。例如,我们可以选择使用更低精度的浮点数类型,以减少内存使用和计算时间,只要这不会对计算结果的精度产生重大影响。
4.增强问题解决能力:理解浮点数精度问题可以增强我们的问题解决能力。当我们遇到与浮点数精度相关的问题时,我们可以更快地识别问题,更有效地找到解决方案。

如何在实际编程中应用这些知识

1.选择合适的数值类型:根据计算的精度需求,我们可以选择使用不同精度的浮点数类型,或者使用定点数或高精度数值库。例如,在需要高精度计算的场景中,我们可以选择使用更高精度的浮点数类型,或者使用高精度数值库。
2.使用容差比较浮点数:由于精度问题,直接比较两个浮点数是否相等可能会出现问题。我们可以使用容差(如绝对误差或相对误差)来进行比较,以避免误差。
3.避免误差累积和误差放大:在进行浮点数运算时,我们需要注意避免误差累积和误差放大。例如,我们可以尽量减少浮点数运算的次数,或者使用数值稳定的算法。
4.测试和验证:在编写程序后,我们需要进行测试和验证,以确保程序的正确性和精度。我们可以使用各种测试方法和工具,如单元测试、断言、浮点数比较工具等。

引言小结论

计算机:二进制的问题,关我计算机什么事?有本事你不用二进制。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值