Python中用于计算gcd的模运算问题

时间:2015-01-23 12:20:52

标签: python numpy

我发现了python模运算的一些奇怪行为。命令

a = 1.0 % 0.1

产量

a == 0.09999999999999995

这是一个非常大的错误,在计算两个浮点数的最大公约数时会出现问题。我想这个错误与二进制(http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems)中的非表示性0.1和1.0有关。是否存在针对此问题的解决方法,或者是否有人指出我可靠的函数来计算两个数字的gcd?到目前为止我用来计算gcd的代码是

def gcd(a, b):
    a, b = np.broadcast_arrays(a, b)
    a = a.copy()
    b = b.copy()
    pos = np.nonzero(b)[0]
    while len(pos) > 0:
        b2 = b[pos]
        a[pos], b[pos] = b2, a[pos] % b2
        pos = pos[b[pos]!=0]
    return a

使用分数模块时遇到同样的问题。

3 个答案:

答案 0 :(得分:3)

您可以使用decimal模块。

from fractions import gcd
from decimal import Decimal
a,b  = 1.0,0.1
print(gcd(Decimal(str(a)),Decimal(str(b))))
0.1
a,b  = 22.8,9.3
print(gcd(Decimal(str(a)),Decimal(str(b))))
0.3

答案 1 :(得分:1)

你可以尝试在python中使用Decimal来不依赖于float“errors”。

>>> from decimal import Decimal as D
>>> a = D(1.0) % D(0.1)
>>> a
Decimal('0.09999999999999995003996389187')

答案 2 :(得分:1)

一个非常简单的hack可以使用普通的numpy浮点数组,可以在取模数之前将ab乘以一些大的因子:

def gcd(a, b, fac=1E12):
    a, b = np.broadcast_arrays(a, b)
    a = a.copy() * fac
    b = b.copy() * fac
    pos = np.nonzero(b)[0]
    while len(pos) > 0:
        b2 = b[pos]
        a[pos], b[pos] = b2, a[pos] % b2
        pos = pos[b[pos]!=0]
    return a / fac

print(gcd(np.r_[1.0, 22.8], np.r_[0.1, 9.3]))
# [ 0.1  0.3]

这种方法优于使用decimal模块的一个优点是你仍然可以利用numpy的矢量化数组操作的速度。由于decimal.Decimal只能表示标量,否则您必须遍历输入数组中的元素并单独处理它们。