方式一:round()
四舍五入
Python中的 round()
有两个参数,第一个参数是需要处理的数,第二个参数是数位精度,默认为0。
round(3.4)
## 3
round(3.5)
## 4
而有时候会出现奇怪的情况,比如:
round(3.24, 1) #是四舍五入
## 3.2
round(3.26, 1) #是四舍五入
## 3.3
round(3.25, 1) #不是四舍五入
## 3.2
###################################
round(0.44, 1) #是四舍五入
## 0.4
round(0.46, 1) #是四舍五入
## 0.5
round(0.45, 1) #是四舍五入
## 0.5
很多人说Python3中采用的是【四舍六入五留双】,上面的例子说明这种说法是不正确的。其实是因为:
- 十进制小数在计算机内是通过二进制小数来近似,在舍和进两个选项中选择更接近的一个
- 而当舍和进的两个选项十分接近时,
round
选择偶数的选项
这就导致出现的结果非常复杂了。
进一步解释:十进制小数 $0.2$
和 $0.3$
的二进制表示分别为:
$$ \begin{align} (0.2)_{10} & = \left(\frac{1}{8}+\frac{1}{16}\right)+\left(\frac{1}{128}+\frac{1}{256}\right)+\cdots =\frac{\frac{1}{8}+\frac{1}{16}}{1-\frac{1}{16}} =\frac{3}{15}=\frac{1}{5}\newline &=(0.\dot{0}\dot{0}\dot{1}\dot{1})_2 \end{align} $$
以及
$$
\begin{align}
(0.3)_{10} & = \frac{1}{4}+\frac{1}{16}+\frac{1}{64}\cdots
=\frac{\frac{1}{4}}{1-\frac{1}{4}}
=\frac{1}{3}\newline
&=(0.\dot{0}\dot{1})_2
\end{align}
$$
照第一条规则,由于存在截断,$0.2$
和 $0.3$
实际存储的数均小于本身,理应 $0.3$
更接近 $0.25$
。然而可能由于两者和 $0.25$
的差距都非常小,根据第二条规则选择了前者。
因此实际中使用 round
会遇到不少bug。
在Python中对小数进行四则运算可以考虑使用 decimal
模块。
from decimal import Decimal
0.3 - 0.25
## 0.04999999999999999
Decimal(0.3) - Decimal(0.25)
## Decimal('0.04999999999999998889776975375')
Decimal("0.3") - Decimal("0.25")
## Decimal('0.05')
方式二: math.ceil()
向上保留
math
模块的 ceil
函数返回大于等于输入值的最小整数,注意输入值为正或负的情形:
from math import ceil
ceil(2.1)
# 3
ceil(-2.1)
# -2
方式三: math.floor()
向下保留
math
模块的 floor
函数返回小于等于输入值的最大整数,注意输入值为正或负的情形:
from math import floor
floor(2.1)
# 2
floor(-2.1)
# -3
方式四:int()
保留整数部分
int
纯粹返回整数部分:
int(2.1)
# 2
int(-2.1)
# -2
也就是说 $$ \text{int}(x)= \begin{cases} \text{math.floor}(x),&x\geq 0\newline \text{math.ceil}(x),&x<0 \end{cases} $$
方法五:使用 numpy
模块
numpy
模块中包含上述所有函数,使用该模块最大的好处就是可以作用于数组上!
round
import numpy as np
np.round([2.25, -2.25], 1)
## array([ 2.2, -2.2])
ceil
np.ceil([-2.2, 2.2])
## array([-2., 3.])
floor
np.floor([-2.2, 2.2])
## array([-3., 2.])
int
np.trunc([-2.2, 2.2])
## array([-2., 2.])
np.int_([-2.2, 2.2])
## array([-2, 2])
numpy
模块中还有一个rint
函数,返回的是最近的整数:
np.rint([-1.45, 1.45])
## array([-1., 1.])
np.int_(np.round(([-1.45, 1.45])))
## array([-1, 1])