有没有一种不使用浮点数而四舍五入到最接近整数的简单的Python方法?我想用整数运算来做下面的事情:
skip = int(round(1.0 * total / surplus))
==============
@约翰:浮点不能跨平台复制。如果你想让你的代码通过不同平台的测试,那么你需要避免浮点(或者在你的测试中添加一些蹩脚的Espilon东西,希望它能起作用)上面的内容可能很简单,在大多数/所有平台上都是一样的,但我宁愿不做这样的决定,因为完全避免浮点更容易。这怎么会“不符合Python的精神”呢?
7条答案
按热度按时间yizd12fk1#
您可以非常简单地执行此操作:
(n + d // 2) // d
,其中n
是被除数,d
是除数。像
(((n << 1) // d) + 1) >> 1
或等效的(((n * 2) // d) + 1) // 2
这样的替代方法在最近的CPython中可能会比较慢,其中int
的实现方式与旧的long
类似。简单方法执行3次变量访问、1次常量加载和3次整数运算。复杂方法执行2次变量访问、3次常量加载和4次整数运算。整数运算可能需要花费时间,这取决于所涉及数字的大小。函数局部变量的变量访问不涉及“查找”。
如果你真的对速度很绝望,做基准测试。否则,吻。
egdjgwm82#
左移一位等于乘2,右移一位等于除2,中间加1使得如果结果大于0.5的小数部分,“向下舍入”实际上就是向上舍入。
这基本上是一样的,如果你写...
除了将所有值乘以2,然后再除以2,这是可以用整数运算来实现的(因为移位不需要浮点)。
eqqqjvef3#
TL;DR:
此解决方案:
rnd(0.5)=0
,rnd(1.5)=2
),这与OP使用的python的round
函数的行为相匹配divmod
文档)完整的故事
灵感源自zhmyh's answer答案,即
,我想出了以下解决方案**(更新:这仅适用于非负的总计和盈余,如注解中所指出的)**:
由于OP要求四舍五入到最近的整数,zhmhs的解决方案实际上有点不正确,因为它总是四舍五入到下一个更大的整数,而我的解决方案只对非负总数和盈余有效。一个对负数也有效的正确解决方案是:
请注意,如果
2 * r == surplus
,则基本上会对正负结果执行取上限,例如ceil(-1.5) == -1
,而ceil(1.5) == 2
。就舍入到最接近的整数而言,这仍然是正确的行为(因为到下一个更小整数和下一个更大整数的距离相等),但是它关于零是不对称的。离零取整一半,我们可以添加一个布尔条件:更妙的是,将取整到最接近的偶数,就像OP使用的python的
round
函数一样:如果您想知道
divmod
是如何定义的:根据文件记载对于整数,结果与
(a // b, a % b)
相同。因此,我们坚持整数运算,如OP所要求的。
smtd7mpg4#
又一个好笑道:
daupos2t5#
在除法之前,只需注意四舍五入规则。对于最简单的四舍五入:
如果你需要做一个适当的四舍五入,稍微调整一下。
jbose2ul6#
问题是你所追求的舍入策略。
下面是我提出的几个例子-注意整数floor和ceiling是case,但是在“舍入到最接近的”中有很多策略。IEEE 754和最专业、工业甚至优雅的方法是舍入到最接近的偶数。我从来没有在任何地方看到过一个在整数运算中这样做的例子。你不能像53那样通过浮点数-位尾数可能会导致精度问题,如果需要执行不同的舍入策略,它已经应用了舍入到最近偶数模式。正确的技术应该始终停留在整数域中
dw1jzc5e7#
这也应该可以: