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: factors
unit 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-operator
unit 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)