
with recursive arg (num) as ( select 2.0^50 - 1-- a number of interest (within int8) ), rec (num, factors) as ( select num :: int8, null :: int8[] from arg union all select num / ff, factors || ff from rec,first_factor(num, factors[ array_length(factors, 1) ]) as ff where ff is not null ) select * from rec; +------------------+------------------------+ | num | factors | +------------------+------------------------+ | 1125899906842623 | | | 375299968947541 | {3} | | 34118178995231 | {3,11} | | 1100586419201 | {3,11,31} | | 4384806451 | {3,11,31,251} | | 7295851 | {3,11,31,251,601} | | 4051 | {3,11,31,251,601,1801} | +------------------+------------------------+ (7 rows)Time: 0.000 ms
↑ の
create or replace function first_factor(int8, int8 default null) returns int8 language sql immutable as $$ with recursive rec (num, fcand, max) as ( select $1, coalesce($2, 2), floor(sqrt($1)) :: int8 union all select num, fcand + case when fcand = 2 then 1 else 2 end, max from rec where fcand <= max ) select fcand from rec where num % fcand = 0 limit 1; $$; -- test select first_factor( (2.0^50 - 1) :: int8 ); +--------------+ | first_factor | +--------------+ | 3 | +--------------+ (1 row)Time: 1.000 ms select first_factor( (2.0^59 - 1) :: int8); +--------------+ | first_factor | +--------------+ | 179951 | +--------------+ (1 row)Time: 97.013 ms

↑ 最小の約数が
with recursive arg (num) as ( select 2.0^52 - 1 ), rec (num, factors) as ( select num :: int8, null :: int8[] from arg union all select num / ff, factors || ff from rec, first_factor(num, factors[ array_length(factors, 1) ]) as ff where ff is not null ) select * from rec; +------------------+------------------------+ | num | factors | +------------------+------------------------+ | 4503599627370495 | | | 1501199875790165 | {3} | | 300239975158033 | {3,5} | | 5664905191661 | {3,5,53} | | 36082198673 | {3,5,53,157} | | 22369621 | {3,5,53,157,1613} | | 8191 | {3,5,53,157,1613,2731} | +------------------+------------------------+ (7 rows)Time: 0.000 ms

↓ 素数でない数で非常に時間かかった例。2^62 - 1
with recursive arg (num) as ( select 2.0^62 - 1 ), rec (num, factors) as ( select num :: int8, null :: int8[] from arg union all select num / ff, factors || ff from rec, first_factor(num, factors[ array_length(factors, 1) ]) as ff where ff is not null ) select * from rec; +---------------------+---------------+ | num | factors | +---------------------+---------------+ | 4611686018427387903 | | | 1537228672809129301 | {3} | | 2147483647 | {3,715827883} | +---------------------+---------------+ (3 rows)Time: 397070.922 ms
大きい素数だと最後まで約数が見つからず延々続くので ↓ こんな風にもっと時間がかかります。2^61 - 1
with recursive arg (num) as ( select 2.0^61 - 1 ), rec (num, factors) as ( select num :: int8, null :: int8[] from arg union all select num / ff, factors || ff from rec, first_factor(num, factors[ array_length(factors, 1) ]) as ff where ff is not null ) select * from rec; +---------------------+---------+ | num | factors | +---------------------+---------+ | 2305843009213693951 | | +---------------------+---------+ (1 row)Time: 850515.002 ms
↓ 素数でも
with recursive arg (num) as ( select 2^31 - 1 ), rec (num, factors) as ( select num :: int8, null :: int8[] from arg union all select num / ff, factors || ff from rec, first_factor(num, factors[ array_length(factors, 1) ]) as ff where ff is not null ) select * from rec; +------------+---------+ | num | factors | +------------+---------+ | 2147483647 | | +------------+---------+ (1 row)Time: 15.600 ms
