费马在Python中的最后定理算法

时间:2017-05-19 06:26:44

标签: python algorithm python-3.x math

我用Python创建了一个程序来寻找Fermat最后定理的解决方案(我知道这是不可解决的,但我只是将它用作编程练习)。费马的最后定理指出:

  

对于n大于2的任何整数值,没有三个正整数a,b和c满足等式a ^ n + b ^ n = c ^ n。

来源:Wikipedia

我的算法(在Python中)在这里:

from fractions import Fraction

def root(num):
    return num ** Fraction(1 / power)

def two_numbers():
    a = b = 1
    while True:
        yield a, b
        if a == b:
            a += 1
            b = 1
        else:
            b += 1

def test(a, b):
    return root((a ** power) + (b ** power)) % 1 == 0

power = int(input('Power: '))

generator = two_numbers()
for a, b in generator:
    result = test(a, b)
    print(a, b, result)
    if result:
        break

当使用12的幂(在提示时输入12)运行时,它将停在:

17 1 True

这可能是由于分数指数的不准确所致。

我怎么知道它是否被舍入,或者否则解决了这个问题?

4 个答案:

答案 0 :(得分:3)

Fraction不能代表无理数,因此即使您使用它也会遇到舍入错误。避免浮点数完全没有留下舍入错误的余地:

def is_perfect_kth_power(n, k):
    low = 1
    high = 1

    # Find an upper bound for the binary search
    while high**k < n:
        high *= 2

    while low + 1 < high:
        midpoint = (low + high) // 2

        if n < midpoint**k:
            high = midpoint
        elif midpoint**k < n:
            low = midpoint
        else:
            return True

    return False

由于你试图找到不存在的东西,我不认为运行时是一个问题。

答案 1 :(得分:1)

是的,

的相对错误的第一个订单项为17
(17**12+1)**(1.0/12)

1.0/(p*a^p) = 1.0/(12*17**12) = 1.43031501388558e-16. 

这小于机器epsilon 2.2e-16,即不足以影响分数功率计算中使用的64位浮点数的尾数。

您可以使用

def test(a, b):
    num=a**power+b**power; 
    c=root(num); 
    return num - int(c+0.5)**power == 0

直到由于从float转换为整数的溢出问题而失败。

您可以反转一阶相对误差的计算。您可以从c大于a的等式得出,因此您需要c至少a+1为整数。插入给出了

 a**p+b**p >= (a+1)**p = a**p + p*a**(p-1) + ...

通过二项式定理,至少你想要

b**p > p*a**(p-1)  <==>  b > a*(p/a)**(1/p)

使用此下限应该避免这些舍入问题。

对于a=17,这会将17作为b的下限,因此无需根据规则b<a进行尝试。对于a=171,下限为138c>=172的第一个案例确实属于b=138

答案 2 :(得分:1)

我会使用以下策略继续使用整数:

  • 对于所需范围内a的所有值,请计算a^n

  • 扫描所需范围内b的所有值并计算a^n + b^n;同时,维护变量c并始终确保(c-1)^n < a^n + b^n <= c^n

随着a^n + b^n的增加,只有右手不等式可能会失效,您可以根据需要多次递增c来修复。要初始化c,只需注意a^n < a^n + 1并以c= a开头即可。

n= 2
m= 50
for a in range(1, m+1):
    an= a ** n
    c= a; cn= an
    for b in range(a+1, m+1):
        anbn= an + b ** n
        while anbn > cn:
            c+= 1
            cn= c ** n
        if anbn == cn: # Bingo!
            print a, b, c

对于案例n=2

3 4 5
5 12 13
6 8 10
7 24 25
8 15 17
9 12 15
9 40 41
10 24 26
12 16 20
12 35 37
14 48 50
15 20 25
15 36 39
16 30 34
18 24 30
20 21 29
20 48 52
21 28 35
24 32 40
24 45 51
27 36 45
28 45 53
30 40 50
33 44 55
36 48 60
40 42 58
...

(请注意,我们从b= a+1开始,以避免重复。)

答案 3 :(得分:0)

在这里,你的问题来自精确。您可以通过以下方式查看:

print(np.finfo(float).eps)
# 2.22044604925e-16

print(np.finfo(np.float32).eps)
# 1.19209e-07

为了更加精确,您可以使用“Decimal”librairie并更新您的根函数:

from decimal import Decimal

def root(num, power):
    return Decimal(num ** Decimal(1 / power))