暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

使用PostgreSQL 暴力计算 亲和数

digoal 2021-01-04
387

作者

digoal

日期

2021-04-14

标签

PostgreSQL , 亲和数


背景

什么是亲和数:

如果两个数a和b,a的所有除本身以外的因数之和等于b,b的所有除本身以外的因数之和等于a,则称a,b是一对亲和数。

https://baike.baidu.com/item/%E4%BA%B2%E5%92%8C%E6%95%B0

  • 320年左右,古希腊毕达哥拉斯发现的220与284,是人类认识的第一对相亲数。 [3]
  • 约850年,阿拉伯数学家塔别脱·本·科拉就发现了相亲数公式,后来称为塔别脱·本·科拉法则。
  • 1636年,费马发现了另一对相亲数:17296和18416。
  • 1638年,笛卡儿也发现了一对相亲数:9363584和9437056。
  • 欧拉也研究过相亲数这个课题。1750年,他一口气向公众抛出了60对相亲数:2620和2924,5020和5564,6232和6368,……,从而引起了轰动。
  • 1866年,年方16岁的意大利青年巴格尼尼发现1184与1210是仅仅比220与284稍为大一些的第二对相亲数。
  • 目前,人们已找到了12,000,000多对相亲数。但相亲数是否有无穷多对,相亲数的两个数是否都是或同是奇数,或同是偶数,而没有一奇一偶等,这些问题还有待继续探索。

首先发现220与284就是一对亲和数,在以后的1500年间,世界上有很多数学家致力于探寻亲和数,面对茫茫数海,无疑是大海捞针,虽经一代又一代人的穷思苦想,有些人甚至为此耗尽毕生心血,却始终没有收获。公元九世纪,伊拉克哲学、医学、天文学和物理学家泰比特·依本库拉曾提出过一个求亲和数的法则,因为他的公式比较繁杂,难以实际操作,再加上难以辨别真假,故它并没有给人们带来惊喜,或者走出困境。数学家们仍然没有找到第二对亲和数。直到费尔马(P.de Fermat,1601-1665)才发现了另一对亲和数:17296和18416。

十六世纪,已经有人认为自然数里就仅有这一对亲和数。有一些无聊之士,甚至给亲和数抹上迷信色彩或者增添神秘感,编出了许许多多神话故事。还宣传这对亲和数在魔术、法术、占星术和占卦上都有重要作用等等。

亲和数的表达公式:
关于后一项工作,早在9世纪,阿拉伯的学者泰比特(TabitibnQorra)就提出了一个构造亲和数的公式:
a=3*2^(x-1)-1, b=3*2^x-1,c=9*2^(2x-1)-1,这里x是大于1的自然数,如果a、b、c全是素数的话。那么2*x*ab2*x*c。便是一对相亲和数。
例如,取x=2,得a=5,b=11,c=71,则2*2*5*11=2202*2*71=284是一对亲和数。

```
postgres=# select (select row(n,sum(i)) r from generate_series(1,n-1) i where mod(n,i)=0) from generate_series(2,300) n;
r


(2,1)
(3,1)
(4,3)
(5,1)
(6,6)
(7,1)
(8,7)
(9,4)
(10,8)
(11,1)
(12,16)
(13,1)
(14,10)
(15,9)
...
(220,284)
...
(284,220)
...
```

使用CTE 暴力计算, 例如计算100000以内的数有没有亲和数:

```
create type fm as (x int, y int);

with a as
(select (select row(n,sum(i)) r from generate_series(1,n-1) i where mod(n,i)=0) from generate_series(2,100000) n)
select t1,t2 from
a t1 join a t2
on
(t1.r::text::fm).x=(t2.r::text::fm).y
and
(t1.r::text::fm).y=(t2.r::text::fm).x
and
(t1.r::text::fm).x <> (t1.r::text::fm).y ;

    t1         |        t2
复制

-------------------+-------------------
("(220,284)") | ("(284,220)")
("(284,220)") | ("(220,284)")
("(1184,1210)") | ("(1210,1184)")
("(1210,1184)") | ("(1184,1210)")
("(2620,2924)") | ("(2924,2620)")
("(2924,2620)") | ("(2620,2924)")
("(5020,5564)") | ("(5564,5020)")
("(5564,5020)") | ("(5020,5564)")
("(6232,6368)") | ("(6368,6232)")
("(6368,6232)") | ("(6232,6368)")
("(10744,10856)") | ("(10856,10744)")
("(10856,10744)") | ("(10744,10856)")
("(12285,14595)") | ("(14595,12285)")
("(14595,12285)") | ("(12285,14595)")
("(17296,18416)") | ("(18416,17296)")
("(18416,17296)") | ("(17296,18416)")
("(63020,76084)") | ("(76084,63020)")
("(66928,66992)") | ("(66992,66928)")
("(66992,66928)") | ("(66928,66992)")
("(67095,71145)") | ("(71145,67095)")
("(69615,87633)") | ("(87633,69615)")
("(71145,67095)") | ("(67095,71145)")
("(76084,63020)") | ("(63020,76084)")
("(79750,88730)") | ("(88730,79750)")
("(87633,69615)") | ("(69615,87633)")
("(88730,79750)") | ("(79750,88730)")
(26 rows)
```

或者使用公式计算

判断是否为素数(质数)?

create or replace function zs(numeric) returns boolean as $$ select count(*) <= 2 from (select 1 from generate_series(1,$1) t where mod($1,t)=0) t; $$ language sql strict;

with t as ( select x, 3*2^(x-1)-1 a, 3*2^x-1 b, 9*2^(2*x-1)-1 c from generate_series(2,100::numeric) as t(x) ) select a,b,c,2*x*a*b,2*x*c from t where zs(a) and zs(b) and zs(c);

PostgreSQL 许愿链接

您的愿望将传达给PG kernel hacker、数据库厂商等, 帮助提高数据库产品质量和功能, 说不定下一个PG版本就有您提出的功能点. 针对非常好的提议,奖励限量版PG文化衫、纪念品、贴纸、PG热门书籍等,奖品丰富,快来许愿。开不开森.

9.9元购买3个月阿里云RDS PostgreSQL实例

PostgreSQL 解决方案集合

德哥 / digoal's github - 公益是一辈子的事.

digoal's wechat

文章转载自digoal,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论