Python - 将浮点数的商安全转换为int

时间:2014-05-31 01:34:02

标签: python casting floating-point

在我的情况下,我试图将一个浮动p除以另一个q。顶部是底部的倍数,两者都具有以下属性:

  1. 十进制正确表示
  2. 最多有3或4位有效数字
  3. 介于11e-8之间。
  4. (例如,p=.0014q=.00002

    在一个完美的世界中,分裂会出现一个完美的整数(这里是70)。但浮点运算是often imperfect

    我希望使用最简单,最安全,最有效的方法来避免在将商转换为p/q - 1时返回int的错误。

    我现在最好的解决办法是做这样的事情:

    int(p/q + 1e-10)
    

    但这可能是不可能的,并且可能效率低下。

    此外,我知道我可以绕圈,但这似乎在代码中具有误导性,并且可能效率低于某种类型的直接演员。

4 个答案:

答案 0 :(得分:2)

你如何处理这些问题,你所做的分工取决于你。也许您应该使用Decimal或Fraction对象,但在评估除法时,Python为此提供了一个模块:

>>> import fractions
>>> fractions.Fraction(.0014/.00002)
Fraction(70, 1)
>>> int(fractions.Fraction(2.3))
2
>>> int(fractions.Fraction(8.35))
8

但在仔细阅读了你的问题之后,我认为你的担忧是不合理的。如果你试图考虑一个分数,由于舍入误差,你将低于一个整数,如果你可以用更高的精度计算,你将在上面,你不能。

例如,下面给出的数字部分永远不会低于1:

>>> fractions.Fraction(1.000000000000001)
Fraction(4503599627370501, 4503599627370496)

在评论中,有人建议到达的股息不在1.64附近。他是如何达到这一点的,他没有说,但正如我在我的介绍中所说的那样,你如何计算分裂点取决于你。

答案 1 :(得分:2)

如果分子是分母的倍数并且商可以准确表示,则浮点除法将给出确切的答案。因此,将顶部分为底部是安全的,如果这是您正在尝试做的事情

但是,您经常使用从十进制转换的数字,或者是某些计算的结果。在这些情况下,您需要弄清楚计算中可能出现多少错误(1.11e-16的相对误差是从十进制转换的安全赌注,除非数字真的很小)并在转换之前将结果缩小到整数。

也就是说,当int((top / bot) * (1 + 2.22e-16))top处于合理范围内时,bot应该做你想做的事。

答案 2 :(得分:2)

从评论中的想法到问题,这是通过decimal

的解决方案
from decimal import Decimal

p = .0014
q = .00002

quotient = int(Decimal(str(p)) / Decimal(str(q)))

当然会产生70

请注意,通过字符串转换似乎是必要的,因为:

>>>print decimal.Decimal(8.4)
8.4000000000000003552713678800500929355621337890625

,而

>>>print decimal.Decimal(str(8.4))
8.4

答案 3 :(得分:0)

似乎到目前为止最直接的解决方案是舍入到int:

int(round(p/q))

或许还附有一条简短的评论,指出pq的倍数,以避免p/q与整数有潜在显着距离的任意暗示。

请注意,此解决方案保证完全安全,因为在这种情况下通过int()进行投射会作用于round()的{​​{3}}浮点数,由float返回。根据用于Python decimal符合的双精度的IEEE浮点标准,这种精确性可保证高达2 53

它可能在显微镜下效率低于其他方式(在问题中提出的建议),但肯定比通过fractions或{{1}}模块处理更有效。并且可能与采用额外乘法和加法的其他解决方案相当。