aboutsummaryrefslogtreecommitdiff
path: root/challenge-139/colin-crain/perl/ch-2.pl
blob: 99ac710665169dd6e476c29f254c32805edfa0ce (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#!/Users/colincrain/perl5/perlbrew/perls/perl-5.32.0/bin/perl
#
#       longpork.pl
#
#       Long Primes
#         Submitted by: Mohammad S Anwar
#         Write a script to generate first 5 Long Primes.
# 
#         A prime number (p) is called Long Prime if (1/p) has an infinite
#         decimal expansion repeating every (p-1) digits.
# 
#         Example
#         7 is a long prime since 1/7 = 0.142857142857...
#         The repeating part (142857) size is 6 
#         i.e. one less than the prime number 7.
# 
#         Also 17 is a long prime since 1/17 = 0.05882352941176470588235294117647...
#         The repeating part (0588235294117647) size is 16 
#         i.e. one less than the prime number 17.
# 
#         Another example, 2 is not a long prime as 1/2 = 0.5.
#         There is no repeating part in this case.


#
#
#       © 2021 colin crain
## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##



use warnings;
use strict;
use utf8;
use feature ":5.26";
use feature qw(signatures);
no warnings 'experimental::signatures';


say '  1/n  |  reptend value';
say '-------+---------------------------------';

for my $val (3..149) {
    next if not  long_prime( $val );
    say sprintf "%5s     %s", $val, get_reptend( $val );
}

sub long_prime ( $num ){
    my $rep = get_reptend( $num );
    return (length $rep == $num - 1)
        ? 1
        : 0 ;
}

sub get_reptend ($div) {
    ## extract the whole-number portion of the quotient in one step
    ## and start the decimal portion with the remainder
    my ($whole, $r) = ediv( 1, $div );

    my $pos = 0;
    my %seen;
    my @q;

    while ($r != 0) {

        ## add one 0 to remainder
        ## add remainder at every index position to %seen hash
        $r .= 0;
        exists $seen{$r} ? last : ($seen{$r} = $pos);
        
        ## add additional 0s to remainder and quotient until num > den
        ## with each 0 increment index position and add to seen hash
        until ($r - $div >= 0) {
            $pos++;
            $r .= 0;
            exists $seen{$r} ? last : ($seen{$r} = $pos);
            push @q, 0;  
        }

        ## the long division step
        my $q;
        ($q, $r) = ediv($r, $div);
        push @q => $q;

        $pos++;
    }

    ## OUTPUT 
    if ($r) {                    
        my $start   = $seen{$r};
        my $end     = $pos-1;
        my @rep     = @q[$start..$end];
        return join '', @rep;
    }
}

sub ediv ( $num, $den ) {   
## Euclidean division of $num by $den returns quotient and remainder
    (int( $num / $den ), $num % $den);
}