Centenary Sequences with Raku

Part 5# Divisors and Factors

by Arne Sommer

Part 5

See also: The Introduction | Part 1: Raku Part 2: Arithmetic and Geometric Sequences | Part 3: Not True, or Not | Part 4: Primes and Fibonacci

The Wikipedia articles referenced in this article does not differentiate between Divisors and Factors. This article defines them differently:

**Divisors**: All the numbers that we can divide the number with. E.g. the
divisors of 20 are: 1, 2, 4, 5, 10 and 20.

**Factors**: All the prime numbers that we can divide the number into. E.g. the
factors of 20 are: 2, 2 and 5.

Divisors are whole numbers that are multiplied together to produce another number. E.g 20 has the following pair of divisors: (1,20), (2,20) and (4,5). Thus the divisors are: 1, 2, 4, 5, 10 and 20.

Note that `1`

and the number
itself are included in the divisors. There are situations where we do not
want them, so the following program supports all combinations:

unit sub MAIN (Int $number);
say "[]: ", divisors($number);
say "[>: ", divisors($number, :not-self);
say "<>: ", divisors($number, :not-self, :not-one);
say "<]: ", divisors($number, :not-one);
sub divisors ($number, :$not-self, :$not-one)
{
my @divisors;
for ($not-one ?? 2 !! 1) .. $number/2 -> $candidate
{
@divisors.push: $candidate if $number %% $candidate;
}
@divisors.push: $number unless $not-self;
return @divisors;
}

Running it:

$ ./divisors 100
[]: [1 2 4 5 10 20 25 50 100] # 1 and the number itself included
[>: [1 2 4 5 10 20 25 50] # 1 included, but not the number itself
<>: [2 4 5 10 20 25 50] # Neither included
<]: [2 4 5 10 20 25 50 100] # 1 not included, but the number itself is

We can use this procedure to set up some sequences, where we include 1 and the number itself. (The next 3 sequences are all computed by the «divisors-applied» program, available in the zip file.)

(1..Inf).map({ divisors($_).elems }); # 057

> say (1..Inf).map({ divisors($_).elems })[^20];
(1 2 2 3 2 4 2 4 3 4 2 6 2 4 4 5 2 6 2 6)

As Divisors, but excluding the number itself. (The `[>`

line from the
«divisors» program.)

(1..Inf).map({ [*] divisors($_, :not-self) }); # 058

> say (1..Inf).map({ divisors($_, :not-self).elems })[^20];
(1 1 1 2 1 6 1 8 3 10 1 144 1 14 15 64 1 324 1 400)

(1..Inf).map({ divisors($_, :not-self).sum }); # 059

> say (1..Inf).map({ divisors($_, :not-self).sum })[^20];
(0 1 1 3 1 6 1 7 4 8 1 16 1 10 9 15 1 21 1 22)

(1..Inf).grep({ $_ > divisors($_, :not-self).sum }) # 060

> say (1..Inf).grep({ $_ > divisors($_, :not-self).sum })[^20];
(1 2 3 4 5 7 8 9 10 11 13 14 15 16 17 19 21 22 23 25)

I have included the program «deficient-numbers» in the zip file.

(1..Inf).grep({ $_ < divisors($_, :not-self).sum }) # 061

> say (1..Inf).grep({ $_ < divisors($_, :not-self).sum })[^20];
(12 18 20 24 30 36 40 42 48 54 56 60 66 70 72 78 80 84 88 90)

I have included the program «abundant-numbers» in the zip file.

(1..Inf).grep({ $_ eq divisors($_, :not-self).sum }); # 062

> say (1..Inf).grep({ $_ eq divisors($_, :not-self).sum })[^3];
(6 28 496)
> say (1..Inf).grep({ $_ eq divisors($_, :not-self).sum })[^4];
(6 28 496 8128)

The first one is fast, but the second one took about 16 seconds. I wisely stopped there...

I have included the program «perfect-numbers» in the zip file.

An Almost Perfect Number
(sometimes also called *Slightly Defective* or *Least Deficiente* Number)
is a natural number `n`

such that the sum of all divisors of `n`

is equal to `2n − 1`

.

(1..Inf).grep({ divisors($_).sum == 2 * $_ - 1 }); # 063

> say (1..Inf).grep({ divisors($_).sum == 2 * $_ - 1 })[^12];
(1 2 4 8 16 32 64 128 256 512 1024 2048)

Note that this is a more time consuming way of generating the «Double the Value» sequence from Part 2: Arithmetic and Geometric Sequences.

I have included the program «almost-perfect-numbers» in the zip file.

An Arithmetic Number is an integer for which the average of its positive divisors is also an integer:

(1..Inf).grep({ my @d = divisors($_); @d.sum %% @d.elems }) # 064

> say (1..Inf).grep({ my @d = divisors($_); @d.sum %% @d.elems })[^25];
(1 3 5 6 7 11 13 14 15 17 19 20 21 22 23 27 29 30 31 33 35 37 38 39 41)

I have included the program «arithemetic-numbers» in the zip file.

A Sublime Number
has a *Perfect Number* of *Positive Divisors*, and those
*Positive Divisors* add up to another *Perfect number*.

There are only two numbers in this sequence, so we can cheat and state them directly:

(12, # 065
6086555670238378989670371734243169622657830773351885970528324860512791691264)

The Factors of a number is a list of prime number we multiply together to get the number. The number itself is the only factor for prime numbers, and the number 1.

File: factorsunit sub MAIN (Int $number where $number > 0, :u(:$upto));
$upto
?? ( say "$_: " ~ factors($_) for 1..$number )
!! say factors($number);
sub factors ($number is copy)
{
return (1) if $number == 1;
return ($number) if $number.is-prime;
my @factors;
for (2 .. $number div 2).grep( *.is-prime) -> $candidate
{
while $number %% $candidate
{
@factors.push: $candidate;
$number /= $candidate;
}
}
return @factors;
}

Running it:

$ ./factors 10
[2 5]

With «upto» mode:

$ ./factors -u 20
1: 1
2: 2
3: 3
4: 2 2
5: 5
6: 2 3
7: 7
8: 2 2 2
9: 3 3
10: 2 5
11: 11
12: 2 2 3
13: 13
14: 2 7
15: 3 5
16: 2 2 2 2
17: 17
18: 2 3 3
19: 19
20: 2 2 5

(1..Inf).map({ factors($_).sum }); # 066

> say (1..Inf).map({ factors($_).sum })[^25];
(1 2 3 4 5 5 7 6 6 7 11 7 13 9 8 8 17 8 19 9 10 13 23 9 10)

The number 20 is an attractive number, whose prime factors are 2, 2 and 5. The number of prime factors is 3, which is also a prime number.

(1..Inf).grep({ factors($_).grep( *.is-prime).elems.is-prime }); # 067

> say (1..Inf).grep({ factors($_).grep( *.is-prime).elems.is-prime })[^20];
(4 6 8 9 10 12 14 15 18 20 21 22 25 26 27 28 30 32 33 34)

I have included the program «attractive-numbers» in the zip file.

This has nothing to do with *Factors* (Divisors), except the name similarity.
But here they are, nevertheless.

The (postfix) Factorial Operator, which Raku is missing, is written as
`4!`

by mathematicians. This is the same as
`4! = 4 * 3 * 2 * 1 = 24`

Raku makes it easy to add the missing operator:

File: factorial-operatorunit sub MAIN (Int $number = 20);
sub postfix:($n)
{
return [*] 1 .. $n;
}

$ ./factorial-operator 3
6
$ ./factorial-operator 10
3628800

(my $i=1, * * $i++ ... Inf) # 068

> say (my $i=1, * * $i++ ... Inf)[^10];
(1 1 2 6 24 120 720 5040 40320 362880)

That looks ok, as long as you accept that the first value (with index 0) is the
value of `0!`

.

The number of digits in the factorial values, instead of the numbers themselves:

(my $i=1, * * $i++ ... Inf).map( *.chars ) # 069

> say (my $i=1, * * $i++ ... Inf).map( *.chars )[^30]
(1 1 1 1 2 3 3 4 5 6 7 8 9 10 11 13 14 15 16 18 19 20 22 23 24 26 27 29 30 31)

The Exponential Factorials start with the number 1 (at index 0). After that we take the index and raises it to the power of the previous number in the sequence:

(my $i=1, $i++ ** * ... Inf) # 070

> say (my $i=1, $i++ ** * ... Inf)[^5]
(1 1 2 9 262144)

The next value is enormous:

> say (my $i=1, $i++ ** * ... Inf)[5].chars;
183231

The Alternating Factorials start with the number 1 (at index 1). After that we take the factorial of the index and subtract the previous number in the sequence:

(my $i = 1, { $i++; ( [*] 1 .. $i ) - $^a } ... Inf) # 071a

> say (my $i = 1, { $i++; ( [*] 1 .. $i ) - $^a } ... Inf)[^10];
(1 1 5 19 101 619 4421 35899 326981 3301819 36614981 442386619)