正文
什么是浮点数呢?通俗来说就是
小数
。我们知道,二进制是很方便地表示十进制整数的,如整数
25 = 16 + 8 + 1
. 因此25的
二进制
表示就是
00011001
,只要给的二进制位数足够多,就可以精确地表示任意一个整数。对于一个
byte
的空间
(8个二进制位
),可以表示
0 - 255
的整数
(00000000 - 11111111)
。
但是小数怎么用二进制表示呢?————将小数部分与整数部分分别表示,我们假设用
2个byte
来储存一个小数
7.375
,则
整数
部分表示为
00000111
(1+2+4,二进制的三个1分别表示2的二次方、一次方、零次方),
小数
部分表示为
01100000
(0.25 + 0.125,二进制的两个1分别表示2的负二次方和负三次方,相加得0.375),因此该数字表示为
00000111 01100000.
看起来一切都很完美,但一个坏消息是,这种表示方法,无法精确地表示某些十进制小数,如
0.1就无法被二进制精确表示
,用来存储小数部分的空间越大,则表示得越精确,但永远无法准确表示。
这样一来似乎问题变得“
无解
”,我们无法精确计算一个数字的原因竟然是,计算机无法精确表示1.1这样的浮点数,这一问题在计算精度要求比较低时,尚不会有严重问题,但当
某些特殊环境下
,如计算一个每月
持续上浮10%
的股票时,这一误差会被迅速放大,给模型带来
巨大
的困扰。
令人
惊喜
的是,Python提供了专门的模块来解决这个问题,即
decimal
模块,
decimal的含义是十进制
,顾名思义,decimal模块用于在计算机中存储“
真正的十进制数
”。decimal模块解决浮点数表达的思路是,
抛弃二进制
计算方式,
直接以十进制
的方式直接进行计算,将小数以“字符串”的形式存储起来,当使用该“字符串”进行计算时,得到的依然是“
字符串
”(
也就是Decimal类的实例
)。但悲喜总是相伴而生,当我们在电脑上使用十进制方法进行计算时,其
速度
自然远远
不如
二进制数的计算速度。但如果遇到对计算精度要求非常高的需求时,必要的效率上的牺牲是非常值得的。
1. 生成decimal类型的小数
In [1]: import decimal
In [2]: a = decimal.Decimal('1.1')
In [3]: a * a
Out[3]: Decimal('1.21')
我们使用
decimal
模块中的类Decimal初始化了
1.1
这个小数,并生成名为
a
的Decimal对象,接着输出
a * a
,返回的依旧是一个Decimal对象,值为
1.21
。
2. 特殊值表示
除了普通的数字值,Decimal 还可以表示很多
特殊值
,包括
正负无穷大值
、“
不是一个数
”(NaN)
In [11]: decimal.Decimal('NaN') ,decimal.Decimal('-NaN')
Out[11]: (Decimal('NaN'), Decimal('-NaN'))
In [12]: decimal.Decimal('Infinity'