最近开始复习、深挖 Python 基础知识,有机会深入探索一些以前没有想过的事情。
我们知道,Python 内置函数 int
和 round
可以把一个浮点数取整,比如
1 | 1.1) int( |
它们是如何工作的呢?
int
函数
1 | int(x, base=10) |
本文中我们不关注一个数的进制,统一按十进制处理。我们来看一个例子:
1 | print(int(1.1)) # 1 |
看起来 int
函数就是简单地截取小数点前面的数值。
round
函数
1 | round(x, ndigits=None) |
这里 round
的处理近似于四舍五入,我们先看几个没有争议的例子:
1 | print(round(1.1)) # 1 |
现在有意思的时候到了,.5
应该如何进位呢?
1 | print(round(1.5)) # 2 |
根据官方文档,rounding 会选择被 2 整除的数,所以 1.5 和 2.5 的 rounding 都是 2。当 ndigits
取非 0 值时,这个原则仍然适用。
1 | print(round(1.55, 1)) # 1.6 |
上述例子中的 ndigits
在为 0 时为 None
,取 0 会有什么变化吗?
1 | round(1.1, ndigits=None) # 1 |
是有变化的!如果 ndigits=None
或者干脆省略,返回一个整数;如果 ndigits=0
,返回一个带有一位小数点的整数。无独有偶,numpy
,TensorFlow
和 PyTorch
也有 numpy.round
,tensorflow.math.round
和 torch.round
与 Python 原生 round
函数对应,它们与原生函数有什么区别呢?
1 | print(np.round(1.5)) # 2.0 |
可以看到,numpy,TensorFlow 和 PyTorch 的 round
函数的工作原理与 Python 原生函数相同。顺便提一句,TensorFlow 和 PyTorch 的 round
函数只能取整,返回一个带有一位小数点的整数;numpy 的 round
函数与 Python 原生函数相同,但是变量名不是 nsdigits
而是 decimals
。
Python 里的相除取整(//
)与相除取余(%
)
所谓的相除取整和相除取余很好理解,就是一个除法如果不能整除的话就分别取整除部分和余数部分:
1 | print(123 // 10) # 12 |
本来很简单的一件小事遇到负数就有意思了:
1 | print(-123 // 10) # -13 |
相除取整
我们把几个除法的结果比较一下:
1 | print(123 / 10) # 12.3 |
在没有看函数源代码的情况下,我们可以大概说,//
操作为向下取整。如果想要一个负结果的向上取整的结果,可以使用 int
配合普通除法。负数除以一个负数与正数除以一个正数的结果相同。
相除取余
还是比较几个除法取余的结果:
1 | print(123 % 10) # 3 |
其实在 Python 中,取余的计算公式与别的语言并没有什么区别:
$$r = a - n * [a // n]$$
其中 r
是余数,a
是被除数,n
是除数。不过在 a // n
这一步,当 a
是负数的时候,上面提到会向下取整,所以有:
$$-123 % 10 = -123 - 10 * (-123 // 10) = -123 - 10 * (-13) = 7$$
其余的两个相除取余也可以按照此法推演出来。