首页 > 其他分享 >浮点数怎样才能没有误差?

浮点数怎样才能没有误差?

时间:2022-12-01 11:08:23浏览次数:75  
标签:误差 decimal 10 有效数字 浮点数 位数 怎样才能 Decimal





浮点数怎样才能没有误差?_有效数字

浮点数怎样才能没有误差?_浮点数_02




我们都知道,任何数据到了计算机中都只可能是二进制,浮点数也没有例外,正因为如此,有些浮点数在存储过程中会产生精度丢失,比如 0.2。那么有没有什么方式来阻止浮点数的精度丢失,其实很简单,自己实现一个浮点数的类然后定义各种方法不就行了吗?这确实可行,但是就没有别人帮我实现好吗?其实早就有了,它就是模块 decimal。


不要使用浮点数



我们先来初步看看模块 decimal 的使用方法,代码如下:

>>> 1.0 // 0.2
4.0
>>> 1.0 % 0.2
0.19999999999999996
>>> import decimal
>>> decimal.Decimal(1.0) // decimal.Decimal(0.2)
Decimal('4')
>>> decimal.Decimal(1.0) % decimal.Decimal(0.2)
Decimal('0.1999999999999999555910790150')
>>> decimal.Decimal('1.0') // decimal.Decimal('0.2')
Decimal('5')
>>> decimal.Decimal('1.0') % decimal.Decimal('0.2')
Decimal('0.0')

上面两个命令我就不给大家讲解了,之前我在讲​​为什么有些小数在计算机中表示有误差?!​​为了发现浮点数的表示问题就给大家演示过同样的例子。之后导入模块 decimal,然后我们调用 decimal.Decimal 类分别传入 1.0 和0.2 这两个数创建了两个实例,其值分别是 1.0 和 0.2,但是我们发现整除的结果依旧是 4,求余的结果比上面更接近 0.2,但还是不等于 0.2。什么情况?!decimal 没用?!不不不,我们传入浮点数对应的字符串就会发现它有用了,精度没有丢失。那么为什么浮点数作为参数传进来会有精度的丢失?这是因为浮点数一旦被加载到计算机的存储单元中去它就已经丢失了精度,decimal 模块中的 Decimal 类可不会恢复精度!

当然这里只是演示了两个运算,其他的运算我就不进行演示了,就只是换换运算符而已,一点也不难!

虽然很方便,但是关于模块 decimal 还是有很多地方需要注意的,比如除不尽会怎么样?小数后面有 0 运算的结果后面会不会有 0?……



除不尽与修改精度



接下来我们先来看看除不尽会怎么样,直接上代码。

>>> decimal.Decimal('1') / decimal.Decimal('7')
Decimal('0.1428571428571428571428571429')

我们可以发现小数点后面有 28 位,那么这个 28 位表示什么意思呢?是保留 28 位小数还是保留 28 位有效数字呢?

我们再来看一个例子,如下所示。

>>> decimal.Decimal('1') / decimal.Decimal('70')
Decimal('0.01428571428571428571428571429')

在这里,我们可以发现小数点后面有 29 位,但是小数点后从第 1 个不是 0 的数往后数就是 28 位,因此,我们可以得出结论,这里的 28 位指的不是是 28 位小数,而是 28 位有效数字!



有效数字


接下来我们穿插一点数学内容,说一说有效数字是个什么鬼东西,有效数字指的是一个小数(表示成科学计数法,格式 a×10^n),其中 a 的位数(不算小数点)就是有效数字的位数,就是这么简单!



修改有效数字位数以及一些问题


修改有效数字位数其实很简单,只需要一行代码就可以了。

>>> decimal.getcontext().prec = 1

很简单对不对?在我这里只弄了一位有效数字,我们来看看这样会有什么问题,问题代码如下:

>>> decimal.getcontext().prec = 1
>>> decimal.Decimal('11')
Decimal('11')
>>> decimal.Decimal('1.1') * decimal.Decimal('10')
Decimal('1E+1')

我们可以发现,实例化的过程不会被有效数字位数影响,而运算的过程会被有效数字的位数影响!1.1 * 10 = 1.1 * 10¹,有效数字为 2 位,但是实例化之后发现并没有被指定的有效位数影响,下面进行运算可就被影响了,至于这里是如何影响的,需要再来让大家看几个例子。

>>> decimal.Decimal('1.1') * decimal.Decimal('10')
Decimal('1E+1')
>>> decimal.Decimal('1.5') * decimal.Decimal('10')
Decimal('2E+1')
>>> decimal.Decimal('1.4') * decimal.Decimal('10')
Decimal('1E+1')
>>> decimal.Decimal('1.49999999999') * decimal.Decimal('10')
Decimal('1E+1')
>>> decimal.Decimal('2.5') * decimal.Decimal('10')
Decimal('2E+1')
>>> decimal.Decimal('2.500000000001') * decimal.Decimal('10')
Decimal('3E+1')

我们可以发现,它是靠到最接近的那一个有效数字,如果有两个有效数字离它一样近,最低有效位必须是偶数!

关于有效数字位数,最后我只说一件事:修改有效数字位数改的是有效数字位数的最大值!



小数末尾有 0 以及运算



我们接下来看看小数末尾有 0,运算之后 0 会不会丢,直接给代码。

>>> decimal.Decimal('1.00')
Decimal('1.00')
>>> decimal.Decimal('1.00') + decimal.Decimal('0.20')
Decimal('1.20')
>>> decimal.Decimal('1.00') - decimal.Decimal('0.20')
Decimal('0.80')
>>> decimal.Decimal('1.00') * decimal.Decimal('0.20')
Decimal('0.2000')
>>> decimal.Decimal('1.00') / decimal.Decimal('0.20')
Decimal('5')
>>> decimal.Decimal('1.000') / decimal.Decimal('0.20')
Decimal('5.0')
>>> decimal.Decimal('1.0000') / decimal.Decimal('0.20')
Decimal('5.00')

我们可以发现实例化之后末尾的 0 不丢,运算的时候 + 和 - 一样,小数点对齐算,末尾多余的 0 不丢,乘法末尾对齐,算完之后移动小数点,末尾的 0 不丢。至于除法嘛,和小学讲的一样,同时扩倍,把除数变成一个整数,小数位数看扩倍之后的被除数有几位小数,以倒数第二行输入为例,扩倍之后被除数为 100.0(1 位小数),因此商值也应该有 1 位小数,所以结果为 5.0。

如果有效数字的最大位数不允许,0 还会不会丢?下面我们以乘法为例,看看有效数字的最大位数太小,小数末尾的 0 会不会丢,代码如下:

>>> decimal.getcontext().prec = 1
>>> decimal.Decimal('1.00') * decimal.Decimal('0.20')
Decimal('0.2')
>>> decimal.getcontext().prec = 2
>>> decimal.Decimal('1.00') * decimal.Decimal('0.20')
Decimal('0.20')

我们可以发现,当有效数字的最大位数不允许时,末尾的 0 超出有效数字的最大位数时自然丢失,只留有效数字的最大位数的一部分(末尾的 0 也要留下)。



负数整除和求余



接下来我们来看看负数整除和求余,是不是和之前一样,我们先来看看之正常的整除和求余。

>>> 10 // -3
-4
>>> 10 % -3
-2
>>> -10 // 3
-4
>>> -10 % 3
2
>>> -10 // -3
3
>>> -10 % -3
-1

整除是返回不大于商的最大整数,整除的结果乘上除数再加上余数就是被除数。把它们都换成 decimal.Decimal 实例还一样吗?

>>> decimal.Decimal(10) // decimal.Decimal(-3)
Decimal('-3')
>>> decimal.Decimal(10) % decimal.Decimal(-3)
Decimal('1')
>>> decimal.Decimal(-10) // decimal.Decimal(3)
Decimal('-3')
>>> decimal.Decimal(-10) % decimal.Decimal(3)
Decimal('-1')
>>> decimal.Decimal(-10) // decimal.Decimal(-3)
Decimal('3')
>>> decimal.Decimal(-10) % decimal.Decimal(-3)
Decimal('-1')

在这里整除变掉了,变成和 C 语言整数除是差不多一回事了,向 0 走,求余的逻辑并没有变,结果变是因为整除的结果变了。



结论



最后做个总结,我们可以发现 decimal 虽好,但它不能时时刻刻如你所愿。第一,你实例化的时候传入浮点数精度不会恢复;第二,除不尽不会一直除(有效数字的最大位数给了限制);第三,小数末尾的 0 只要有效数字的最大位数允许,运算之后就不会丢;第四,负数的整除变成向 0 走。

当然,关于模块 decimal 还有很多东西。大家可以自己参考一下官方文档,我就不一一讲解了。

当然,我从今年开始已经入驻 B 站了!下面给出 B 站账号:新时代的运筹帷幄,喜欢的可以关注一下,看完视频不要忘记一键三连啊!

今天的文章有不懂的可以后台回复“加群”,备注:Python 机器学习算法说书人,不备注可是会被拒绝的哦~!



浮点数怎样才能没有误差?_整除_03

扫码关注



标签:误差,decimal,10,有效数字,浮点数,位数,怎样才能,Decimal
From: https://blog.51cto.com/u_15829940/5901355

相关文章

  • 拓端tecdat|R语言编程指导异方差回归模型建模:用误差方差解释异方差
    R语言异方差回归模型建模:用误差方差解释异方差  在社会科学中将OLS估计应用于回归模型时,其中的一个假设是同方差,我更喜欢常误差方差。这意味着误......
  • 怎样才能戒烟
    戒烟需具有自控力,并做好计划,培养新的兴趣爱好,必要时可在戒烟门诊进行治疗。1、戒烟者可将每日吸烟量减半,逐步减少每日吸烟量直至归零。这样可以避免突然戒烟而导致的强烈......
  • 浮点数
    一、浮点数的比较浮点数和整型数在计算机中表示的方式不相同,整型数能够直接比较相等,但是浮点数不能直接比较是否相等,如下:intmain(){intn=0;floatval=1.0,......
  • matlab误差传播和算法稳定性
    算法描述:    方案二:递推公式结果:y(1)=0.212647           y(2)=0.071838           y(3)=0.065374           y(4)=0.046157   ......
  • C语言浮点数
    文章目录​​一、浮点数的概念​​​​二、占用内存的情况​​​​三、浮点数的精度​​​​1、测试float类型​​​​2、测试double类型​​​​3、测试longdouble类型​......
  • C语言把浮点数转换为二进制数的方法和示例
    文章目录​​1、整数部分转二进制字符串的方法​​​​2、小数部分转二进制字符串的方法​​​​3、示例程序​​​​4、获取视频教程​​​​5、版权声明​​浮点数据转换......
  • C# 使用SIMD向量类型加速浮点数组求和运算(3):循环展开
    作者:zyl910目录一、背景1.1循环展开简介1.2测试准备二、在C#中使用2.1对基础算法做循环展开2.1.1测试结果:2.2对Vector4版算法做循环展开2.2.1测试结果:2.3对V......
  • IEEE-754浮点数标准与JavaScript中的number
    1、概述如何使用8个字节表示特定的数字(整数或小数),其中要满足精度足够高,和表示的数字尽可能的大。聪明的你肯定想到使用科学计数法来表示,其中64位中,需要包含确定正负的符号......
  • 浮点数比较和计算机内部数据转换
    浮点数的比较问题问题描述输出:no问题解释计算机内部以二进制储存,一切数据都将转化为二进制储存在计算机中一个小数分为整数部分和小数部分而小数和整数的转化为二......
  • 从0.2+0.4不等于0.6说浮点数
    浮点数的表示从0.2+0.4不等于0.6说浮点数,浮点数我一直心存疑惑。下面文章小数特指十进制数字,浮点数特指计算机存储的格式。现代计算机的一般的浮点数都是遵循IEEE754标准。......