(python)亲和数

前言

        在遥远的古代,人们发现某些自然数之间有特殊的关系:如果两个数a和b,a的所有除本身以外的因数之和等于b,b的所有除本身以外的因数之和等于a,则称a,b是一对亲和数

        据说,毕达哥拉斯, 希腊文Πυθαγόρας,约前580年—前500年)的一个门徒向他提出这样一个问题:“我结交朋友时,存在着数的作用吗?”毕达哥拉斯毫不犹豫地回答:“朋友是你的灵魂的倩影,要像220和284一样亲密。”又说“什么叫朋友?就像这两个数,一个是你,另一个是我。”后来,毕氏学派宣传说:人之间讲友谊,数之间也有“相亲相爱”。从此,把220和284叫做“亲和数”或者叫“朋友数”或叫“相亲数”。这就是关于“亲和数”这个名称来源的传说。220和284是人类最早发现,又是最小的一对亲和数

发现历史

  • 320年左右,古希腊毕达哥拉斯发现的220与284,是人类认识的第一对相亲数。 

  • 约850年,阿拉伯数学家塔别脱·本·科拉就发现了相亲数公式,后来称为塔别脱·本·科拉法则。

  • 1636年,费马发现了另一对相亲数:17296和18416。

  • 1638年,笛卡尔也发现了一对相亲数:9363584和9437056。

  • 1747年,年仅39岁的欧拉也研究过相亲数这个课题。1750年,他一口气向公众抛出了60对相亲数:2620和2924,5020和5564,6232和6368,……,从而引起了轰动。

  • 1866年,年方16岁的意大利青年巴格尼尼发现1184与1210是仅仅比220与284稍为大一些的第二对相亲数。

  • 目前,人们已找到了12,000,000多对相亲数。但相亲数是否有无穷多对,相亲数的两个数是否都是或同是奇数,或同是偶数,而没有一奇一偶等,这些问题还有待继续探索。

亲和数的定义

  • 如果 a和b是一对亲和数,那么 a的所有真因数之和等于b,且b的所有真因数之和等于a
  • 一对亲和数,同为偶数或同为奇数(待推翻,哈哈哈...) 

例如,220和284是一对亲和数

220的真因数:1, 2, 4, 5, 10, 11, 20, 22, 44, 55, 110,它们的和为284。

284的真因数:1, 2, 4, 71, 142,它们的和为220。

欧拉公式

计算亲和数的公式主要有几种,其中最著名的是欧拉公式

注:欧拉公式生成的亲和数对有限,且不是所有亲和数对都可以通过此公式生成。

代码

  1. is_prime 函数:用于检查一个数是否为素数。这个函数使用了基本的素数检测算法,对于较小的数效率较高。
  2. euler_formula 函数:根据欧拉公式生成亲和数对。首先计算 a,b,c,然后检查它们是否都是素数。如果是,计算并返回亲和数对。
  3. 主循环:从 2到 50调用 euler_formula 函数生成亲和数对,并打印结果。
def is_prime(n):
    """检查一个数是否为素数"""
    if n <= 1:
        return False
    if n <= 3:
        return True
    if n % 2 == 0 or n % 3 == 0:
        return False
    i = 5
    while i * i <= n:
        if n % i == 0 or n % (i + 2) == 0:
            return False
        i += 6
    return True

def euler_formula(x):
    """使用欧拉公式生成亲和数对"""
    a = 3 * (2 ** x) - 1
    b = 3 * (2 ** (x - 1)) - 1
    c = 9 * (2 ** (2 * x - 1)) - 1
    
    if is_prime(a) and is_prime(b) and is_prime(c):
        num1 = 2 ** x * a * b
        num2 = 2 ** x * c
        return (num1, num2)
    else:
        return None

# 生成一些亲和数对
for x in range(2, 20):
    pair = euler_formula(x)
    if pair:
        print(f"亲和数对: {pair}")


# 亲和数对: (220, 284)
# 亲和数对: (17296, 18416)
# 亲和数对: (9363584, 9437056)

暴力枚举法

直接说结论吧.

所有100万以下的数逐一进行了检验,总共找到了40对亲和数

发现10万以下数中仅有13对亲和数

小技巧:通过预计算每个数的真因数之和,然后在查找亲和数对时直接使用这些预计算的值,进一步提高了效率

def sum_of_divisors(n):
    """计算一个数的真因数之和"""
    sum_div = 1  # 1 是所有数的真因数
    for i in range(2, int(n**0.5) + 1):
        if n % i == 0:
            sum_div += i
            if i != n // i:
                sum_div += n // i
    return sum_div

def find_amicable_numbers(limit):
    """找到所有小于 limit 的亲和数对"""
    amicable_pairs = []
    sum_divisors = [1] * limit  # 初始化真因数之和数组
    for i in range(2, limit):
        for j in range(i * 2, limit, i):
            sum_divisors[j] += i
    for a in range(2, limit):
        b = sum_divisors[a]
        if b < limit and b > a and sum_divisors[b] == a:
            amicable_pairs.append((a, b))
    return amicable_pairs

# 示例:找到所有小于 10000 的亲和数对
limit = 1000000
amicable_pairs = find_amicable_numbers(limit)
print(f"小于 {limit} 的亲和数对:{amicable_pairs}")
print(len(amicable_pairs))

 总结

        亲和数有着漫长的发现历史和美丽动人的传说。从古希腊的毕达哥拉斯学派到中世纪的阿拉伯数学家,再到近代的费马、欧拉等数学大师,都与亲和数的发现和研究有着密切的联系。这些历史故事和传说为亲和数赋予了浓厚的文化底蕴,使其成为数学史上的一段佳话,也让人们在了解亲和数的过程中,领略到数学发展的历史脉络和人类智慧的传承。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Marst·Zhang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值