Centenary Sequences with Raku
Part 5

Divisors and Factors

by Arne Sommer

Centenary Sequences with Raku - Part 5: Divisors and Factors

[100.5] Published 4. November 2020.

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

Divisors vs Factors

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

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:

File: divisors
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.)

057. Number of Divisors
We can count the number of divisors:

(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)

Perfect Divisors

As Divisors, but excluding the number itself. (The [> line from the «divisors» program.)

058. Multipled Divisors
We can multiply the divisors:

(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)

059. Summed Divisors
We can add the divisors:

(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)

060. Deficient Numbers
A Deficient Number is a number that is larger than the sum of its perfect divisors.

(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.

061. Abundant Numbers
An Abundant Number is a number that is smaller than the sum of its divisors (excluding itself).

(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.

062. Perfect Numbers
A perfect number is a number that is equal to the sum of its perfect divisors. For example, 28=1+2+4+7+14 is a perfect number.

(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.

063. Almost Perfect Numbers

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.

064. Arithmetic Number

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.

065. Sublime Numbers

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)

Factors

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

066. Summed Factors
We can add the factors of the numbers (indices):

(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)

067. Attractive Numbers
A number is an attractive number if the number of its prime factors is also a prime number.

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.

Factorial

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

Adding the Factorial Operator

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

068. Factorial Sequence
We can get the factorial values like this:

(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!.

069. Factorial Number Length

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)

070. Exponential Factorials

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

071. Alternating Factorials

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)

The Next Part

Part 6: Binary and Palindrome.