This is my response to the Perl Weekly Challenge #150.
$a
and $b
.
Fibonacci Words
by concatenation of the previous two
strings. Finally print 51st digit of the first term having at least 51 digits.
Input: $a = '1234' $b = '5678'
Output: 7
Fibonacci Words:
'1234'
'5678'
'12345678'
'567812345678'
'12345678567812345678'
'56781234567812345678567812345678'
'1234567856781234567856781234567812345678567812345678'
The 51st digit in the first term having at least 51 digits
'1234567856781234567856781234567812345678567812345678' is 7.
#! /usr/bin/env raku
subset DigitStr where * ~~ /^<[0..9]>+$/; # [1]
unit sub MAIN (DigitStr $a, DigitStr $b, :v(:$verbose)); # [1]
my $fw := ($a, $b, * ~ * ... *); # [2]
for ^Inf -> $index # [3]
{
my $current = $fw[$index]; # [4]
say ": { $index +1 }: $current" if $verbose;
if $current.chars >= 51 # [5]
{
say $current.substr(50, 1); # [6]
last; # [6a]
}
}
[1] A custom type allowing digits only. Note that the \d
regex will match
any Unicode character that has a numeric digit property, so explisitly allowing the
digits 0-9 is the thing.
[2] The sequence. The first two values as specified in $a
and $b
,
and then we concatenate the two newest values to get the next one.
[3] Iterate over the numbers from 0 and up,
[4] and use that number as index in the Fibonacci sequence.
[5] Do we have enough digits?
[6] if so, print the 51st digit (at index 50, as they are zero based), and exit [6a].
Running it:
$ ./fibonacci-words 1234 5678
7
$ ./fibonacci-words -v 1234 5678
: 1: 1234
: 2: 5678
: 3: 12345678
: 4: 567812345678
: 5: 12345678567812345678
: 6: 56781234567812345678567812345678
: 7: 1234567856781234567856781234567812345678567812345678
7
We can make the program a little shorter:
File: fibonacci-words-while
#! /usr/bin/env raku
subset DigitStr where * ~~ /^<[0..9]>+$/;
unit sub MAIN (DigitStr $a, DigitStr $b);
for ($a, $b, * ~ * ... *) -> $current
{
if $current.chars >= 51
{
say $current.substr(50, 1);
last;
}
}
Running it gives the expected result:
$ ./fibonacci-words-while 1234 5678
7
This is straight forward translation of the Raku version(s), with verbose mode. Perl
does not have sequences, but we can use the $a
and $b
variables to hold the last two values while we loop away (just as we did last week
for the normal Fibonacci sequence; see Fibonacci Square
with Raku and Perl).
#! /usr/bin/env perl
use strict;
use warnings;
use feature 'say';
use Getopt::Long;
my $verbose = 0;
GetOptions("verbose" => \$verbose);
my $a = $ARGV[0] || 1234;
my $b = $ARGV[1] || 5678;
my $i = 4;
die 'Please specify digits only for $a' unless $a =~ /^\d+$/;
die 'Please specify digits only for $b' unless $b =~ /^\d+$/;
say ": 1: $a" if $verbose;
say ": 2: $b" if $verbose;
($a, $b) = ($b, $a . $b);
say ": 3: $b" if $verbose;
while (length($b) < 51)
{
($a, $b) = ($b, $a . $b);
say ": " . $i++ . ": $b" if $verbose;
}
say substr($b, 50, 1);
Running it gives the same result as the Raku version:
$ ./fibonacci-words-perl 1234 5678
7
$ ./fibonacci-words-perl -v 1234 5678
: 1: 1234
: 2: 5678
: 3: 12345678
: 4: 567812345678
: 5: 12345678567812345678
: 6: 56781234567812345678567812345678
: 7: 1234567856781234567856781234567812345678567812345678
7
The smallest positive square-free integers are
1, 2, 3, 5, 6, 7, 10, 11, 13, 14, 15, 17, 19, 21, 22, 23, 26, 29, 30, ...
Let us start with the hard part, the Prime Factors. This is a case of code reuse, as we did just that in Challenge #123.1 Ugly Numbers; see Ugly Points with Raku and Perl, which is also a case of code reuse of the «factors» procedure from the program with the same name in my Centenary Sequences with Raku Part 5 - Divisors and Factors article. (Scroll down to sequence #065).
The rest of the program is quite easy to set up:
File: square-free-integers
#! /usr/bin/env raku
unit sub MAIN (Int $limit where $limit > 0 = 500; # [1]
say (1 .. $limit).grep( { factors($_).repeated.elems == 0 }).join(", "); # [2]
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;
}
[1] Specify another limit if 500 does not suit you.
[2] Hold on to the elemenst that have repeated factors (with
grep
) and print them. The repeated
method removes the first
instance of the values, giving us a list of repetitions (after the first one).
Slapping on .elems == 0
takes care of the rest.
See
docs.raku.org/routine/repeated
for more information about repeated
.
Running it:
$ ./square-free-integers
1, 2, 3, 5, 6, 7, 10, 11, 13, 14, 15, 17, 19, 21, 22, 23, 26, 29, 30, 31, 33,\
34, 35, 37, 38, 39, 41, 42, 43, 46, 47, 51, 53, 55, 57, 58, 59, 61, 62, 65,\
66, 67, 69, 70, 71, 73, 74, 77, 78, 79, 82, 83, 85, 86, 87, 89, 91, 93, 94,\
95, 97, 101, 102, 103, 105, 106, 107, 109, 110, 111, 113, 114, 115, 118, 119,\
122, 123, 127, 129, 130, 131, 133, 134, 137, 138, 139, 141, 142, 143, 145,\
146, 149, 151, 154, 155, 157, 158, 159, 161, 163, 165, 166, 167, 170, 173,\
174, 177, 178, 179, 181, 182, 183, 185, 186, 187, 190, 191, 193, 194, 195,\
197, 199, 201, 202, 203, 205, 206, 209, 210, 211, 213, 214, 215, 217, 218,\
219, 221, 222, 223, 226, 227, 229, 230, 231, 233, 235, 237, 238, 239, 241,\
246, 247, 249, 251, 253, 254, 255, 257, 258, 259, 262, 263, 265, 266, 267,\
269, 271, 273, 274, 277, 278, 281, 282, 283, 285, 286, 287, 290, 291, 293,\
295, 298, 299, 301, 302, 303, 305, 307, 309, 310, 311, 313, 314, 317, 318,\
319, 321, 322, 323, 326, 327, 329, 330, 331, 334, 335, 337, 339, 341, 345,\
346, 347, 349, 353, 354, 355, 357, 358, 359, 362, 365, 366, 367, 370, 371,\
373, 374, 377, 379, 381, 382, 383, 385, 386, 389, 390, 391, 393, 394, 395,\
397, 398, 399, 401, 402, 403, 406, 407, 409, 410, 411, 413, 415, 417, 418,\
419, 421, 422, 426, 427, 429, 430, 431, 433, 434, 435, 437, 438, 439, 442,\
443, 445, 446, 447, 449, 451, 453, 454, 455, 457, 458, 461, 462, 463, 465,\
466, 467, 469, 470, 471, 473, 474, 478, 479, 481, 482, 483, 485, 487, 489,\
491, 493, 494, 497, 498, 499
Looking good.
#! /usr/bin/env perl
use strict;
use warnings;
use feature 'say';
use feature 'signatures';
no warnings 'experimental::signatures';
use Math::Prime::Util 'is_prime';
use List::MoreUtils 'duplicates';
my $limit = $ARGV[0] || 500;
die "Please specify a positive integer" unless $limit =~ /^[1-9]\d*$/;
my @result = grep { ! duplicates factors($_) } (1 .. $limit);
say join(", ", @result);
sub factors ($number)
{
return (1) if $number == 1;
return ($number) if is_prime($number);
my @factors;
for my $candidate (grep { is_prime($_) } 2 .. $number / 2)
{
while ($number % $candidate == 0)
{
push(@factors, $candidate);
$number /= $candidate;
}
}
return @factors;
}
Running it gives the same result as the Raku version:
$ ./square-free-integers-perl
1, 2, 3, 5, 6, 7, 10, 11, 13, 14, 15, 17, 19, 21, 22, 23, 26, 29, 30, 31, 33,\
34, 35, 37, 38, 39, 41, 42, 43, 46, 47, 51, 53, 55, 57, 58, 59, 61, 62, 65,\
66, 67, 69, 70, 71, 73, 74, 77, 78, 79, 82, 83, 85, 86, 87, 89, 91, 93, 94,\
95, 97, 101, 102, 103, 105, 106, 107, 109, 110, 111, 113, 114, 115, 118, 119,\
122, 123, 127, 129, 130, 131, 133, 134, 137, 138, 139, 141, 142, 143, 145,\
146, 149, 151, 154, 155, 157, 158, 159, 161, 163, 165, 166, 167, 170, 173,\
174, 177, 178, 179, 181, 182, 183, 185, 186, 187, 190, 191, 193, 194, 195,\
197, 199, 201, 202, 203, 205, 206, 209, 210, 211, 213, 214, 215, 217, 218,\
219, 221, 222, 223, 226, 227, 229, 230, 231, 233, 235, 237, 238, 239, 241,\
246, 247, 249, 251, 253, 254, 255, 257, 258, 259, 262, 263, 265, 266, 267,\
269, 271, 273, 274, 277, 278, 281, 282, 283, 285, 286, 287, 290, 291, 293,\
295, 298, 299, 301, 302, 303, 305, 307, 309, 310, 311, 313, 314, 317, 318,\
319, 321, 322, 323, 326, 327, 329, 330, 331, 334, 335, 337, 339, 341, 345,\
346, 347, 349, 353, 354, 355, 357, 358, 359, 362, 365, 366, 367, 370, 371,\
373, 374, 377, 379, 381, 382, 383, 385, 386, 389, 390, 391, 393, 394, 395,\
397, 398, 399, 401, 402, 403, 406, 407, 409, 410, 411, 413, 415, 417, 418,\
419, 421, 422, 426, 427, 429, 430, 431, 433, 434, 435, 437, 438, 439, 442,\
443, 445, 446, 447, 449, 451, 453, 454, 455, 457, 458, 461, 462, 463, 465,\
466, 467, 469, 470, 471, 473, 474, 478, 479, 481, 482, 483, 485, 487, 489,\
491, 493, 494, 497, 498, 499
And that's it.