RosettaCodeData/Task/Arithmetic-numbers/DuckDB/arithmetic-numbers.duckdb

71 lines
2.3 KiB
Plaintext

### Preliminaries
# If x is NULL then raise an error condition:
create or replace function try(x, ErrorMessage) as (
if( x IS NULL, error( ErrorMessage ), x )
);
create or replace function proper_divisors(n) as table (
select 1 where n > 1
union all
select distinct i
from (select unnest( [ j, n // j]) as i
from range(2, 1 + sqrt(n).floor()::BIGINT) as t(j)
where (n % j) == 0)
);
create or replace function composite(n) as (
select count(*) == 2 as n from (from proper_divisors(n) limit 2)
);
create or replace function average_is_integral(lst) as (
list_sum(lst) % length(lst) = 0
);
create or replace function list_of_proper_divisors(n) as (
select coalesce(array_agg(i), []) as divisors from proper_divisors(n) t(i)
);
### Arithmetic numbers
# A table of the arithmetic numbers in range(1, mx)
create or replace function arithmetic_numbers(mx) as table (
select n
from range(1, mx) t(n)
where average_is_integral(list_of_proper_divisors(n) || [n])
order by n -- needed
);
# A table (n, composite) of the arithmetic numbers in range(1, mx) showing also whether each is composite
create or replace function describe_arithmetic_numbers(mx) as table (
select n, length(lst) > 1 as composite
from
(select n, list_of_proper_divisors(n) as lst
from range(1, mx) t(n)
where average_is_integral(lst || [n])
order by n -- needed
)
);
# Return a struct {nth, composites} giving the nth arithmetic number
# and the number of composites less than or equal to that number.
# If the heuristic fails, an error is raised.
create or replace function describe_nth_arithmetic_number(nth) as (
with cte as (from describe_arithmetic_numbers(nth * 2) limit nth)
select try(
(select { nth: (select last(n) from cte),
composites: (select count(*) from cte where composite = true)}
where nth = (select count(*) from cte)),
'heuristic failure')
);
# Return a list of the first `number` arithmetic numbers using a
# heuristic cautiously
create or replace function arithmetic_numbers_list(number) as (
with cte as (from describe_arithmetic_numbers(number * 2 ) limit number),
m as (select count(*) as m from cte)
select try(
if (m = number, (select array_agg(n) from cte), null),
'heuristic failure' )
from m
);