cc362c语言错误double,为什么C/C++Python float和double中的浮点计算不准确?显示范围和精度,CCpythonfloatdouble,表示,及...

现象

>>> 1.2 - 1.0

0.19999999999999996

原因:

根本原因:存在(用二进制存储时)“不可表示”,如0.1,0.2和0.01

计算机会把你心里想的十进制小数转换为二进制小数,然后在内存中存储二进制小数

CPython 中的 float 类型使用C语言的 double 类型进行存储。 float 对象的值是以固定的精度(通常为 53 位)存储的二进制浮点数,由于 Python 使用 C 操作,而后者依赖于处理器中的硬件实现来执行浮点运算。 这意味着就浮点运算而言,Python 的行为类似于许多流行的语言,包括 C 和 Java。

许多可以轻松地用十进制表示的数字不能用二进制浮点表示。例如,之后:

1.0011001100110011001100110011001100110011001100110011 (binary)

确切地说:

>>> x = 1.2

1.1999999999999999555910790149937383830547332763671875 (decimal)

在python中,浮点数有53位可用精度,典型的 53 位精度为 Python 浮点数提供了 15-16 位小数的精度。

解决

decimal模块提供了一个数据类型Decimal用于浮点数计算,相比内置的浮点数类型float,Decimal这个类型有助于需要精确十进制表达的场合,或者用户希望计算结果与手算相符的场合。Decimal重现了手工的数学运算,这就确保了二进制浮点数无法精确保有的数据精度。

>>> from decimal import Decimal

>>> from decimal import getcontext

>>> Decimal('4.20') + Decimal('2.10')

Decimal('6.30')

>>> from decimal import Decimal

>>> from decimal import getcontext

>>> x = 4.20

>>> y = 2.10

>>> z = Decimal(str(x)) + Decimal(str(y))

>>> z

Decimal('6.3')

>>> getcontext().prec = 4 #设置精度

>>> Decimal('1.00') /Decimal('3.0')

Decimal('0.3333')

具体范围和 精度原理

浮点数存储方法

首先要搞清楚浮点数在内存中的存储方式。浮点数,区别于定点数,指的是

小数点位不确定

的的数据类型,其原理是将一个浮点数a用两个数m(尾数)和e(指数)来表示:a = m × b^e。其中的b为选取的基数。科学计数法就是一种特殊形式的浮点数。

在计算机二进制表示中,浮点数采用

2作为基数,规定尾数的范围为1.0~2.0之间

以float类型为例,根据最广泛采用的IEEE754标准规定,

float数据类型长度为32位,其中最高位为符号位,中间8位为指数位,最后23位作为尾数位。

符号位

最高位符号位通过0/1来区分正负,0正1负;

指数位

指数位则规定采用移码的形式存储,这样可以保证指数部分为无符号数,方便比较大小。移码表示法是在数X上增加一个偏移量来定义的,如果机器字长为n,规定偏移量为2^(n-1),对于8位补码-128~ 127,可得到对应的阶码表示为0 ~ 255,其中0和255分别用来表示0和无穷大,1~ 254用来表示规范数字,即

指数范围从-126到127

尾数位

尾数部分统一规定为

1.0-2.0之间

,最高位必然为1,故可以省略,所

以尾数部分从小数点后

算起,

最小可以取到1(小数点位全为0),最大则取到二进制1.1…1(小数点后23位全为1)

,即取到(2减去2

-23

),可近似约等于2。

范围

故得到float绝对值的最大值取到2

127

*(2-2

-23

)约等于2

128

=3.4E+38。加上符号之后可得float表示范围为(-3.4E+38)~(3.4E+38)。当然实际是取不到的,开区间。绝对值最小则可以取到2^-127 *1,即为1.175E-38。

精度

接下来解释精度。由于尾数部分位数是固定的小数点后23位,

23位所能表示的最大数是2^23−1=8388607

,所以十进制的尾数部分最大数值是8388607,也就是说尾数数值超过这个值之后,float将无法精确表示,

所以float最多能表示小于8388607的小数点后7位

,但

绝对能保证的为6位

,也即float的十进制的精度为为6~7位。

double

double数据类型的推算过程和上述同理,唯一的区别在于尾数由23位扩展到52位,阶码由8位增加到了11位,计算方法不变。所以double的阶码(移码表示)为0

2047,偏移量为1024,故指数范围为-1024

1023,得表示范围为(2

1023*2)~(-2

1023*2)即为-1.7E+308~1.7E+308,绝对值最小可以取到2

-1024

,精度则为2

52

-1=4503599627370495,为16位。所以精度最高位16位,一定可以保证15位。

plus

int和long都是用32位来存储最大值和最小值分别为2147483647(2^31-1 ~ 10^9), -2147483648(-2^31);

long long 是用64位来存储最大值和最小值分别为9223372036854775807(10^18),-9223372036854775808;

float的最大值和最小值分别为3.40282e+038(10

38

),1.17549e-038(10^-38);

double的最大值和最小值分别为1.79769e+308(10

308),2.22507e-308(10

-308)。

https://blog.csdn.net/black_kyatu/article/details/79257346

ref

https://blog.csdn.net/zhouxufeng1996/article/details/94999514?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值