aboutsummaryrefslogtreecommitdiff
path: root/challenge-159/colin-crain/perl/ch-1.pl
blob: 2cff1df4fb5788af2360535e44a3a963a099a67f (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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#!/Users/colincrain/perl5/perlbrew/perls/perl-5.32.0/bin/perl
#
#       fareys-wear-boots.pl
#
#         Farey Sequence
#         Submitted by: Mohammad S Anwar
#         You are given a positive number, $n.
# 
#         Write a script to compute Farey Sequence of the order $n.
# 
#         Example 1:
#             Input: $n = 5
#             Output: 0/1, 1/5, 1/4, 1/3, 2/5, 
#                     1/2, 
#                     3/5, 2/3, 3/4, 4/5, 1/1
# 
#         Example 2:
#             Input: $n = 7
#             Output: 0/1, 1/7, 1/6, 1/5, 1/4, 2/7, 1/3, 2/5, 3/7, 
#                     1/2, 
#                     4/7, 3/5, 2/3, 5/7, 3/4, 4/5, 5/6, 6/7, 1/1
# 
#         Example 3:
#             Input: $n = 4
#             Output: 0/1, 1/4, 1/3, 
#                     1/2, 
#                     2/3, 3/4, 1/1
# 
#         method:
# 
#             The Fahey sequence or a given order n is a list of all
#             subunary fractions with denominators up to the value of the
#             order, reduced to their lowest terms and placed in ascending
#             order. One interesting property of this sequence is that for
#             any triplet of successive terms selected, the central term
#             will be the mediant of the two outer, which is to say we can
#             obtain the ratio of the intermediate value by summing the two
#             numerators and two denominators of the outside terms: for the
#             two terms in example 2 above 2/7 and 2/5 the intermediate
#             numerator is 2+2 and denominator is 7+5, yielding 4/12, wich
#             can be reduced to 1/3. This can be seen to be the case by
#             examination of the example.
# 
#             Two algorithms suggest themselves to produce the Fahey
#             sequence for a given order: we can either construct all the
#             fractions exhaustively, reduce them to their lowest terms,
#             remove duplicates and sort them; or alternately we can bisect
#             each set of adjacent fractions in the the previous order to
#             construct the next, reducing them as possible along the way,
#             until we arrive at the order requested. 
#
#             As it 
#       © 2022 colin crain
## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##



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


package Rat;
{
    use Moo;
    use feature qw(signatures);
    no warnings 'experimental::signatures';

    has n => ( is => 'ro');
    has d => ( is => 'ro');

    has num => ( is => 'rw');
    has den => ( is => 'rw');
    has val => ( is => 'rw');
    
    around BUILDARGS => sub {
        my ( $orig, $class, @args ) = @_;
        return {    n => $args[0],
                    d => $args[1]  };        
    };
 
    sub BUILD ($self, $args) { 
        my $gcd = gcd( $self->n, $self->d );           
        $self->num( $self->n / $gcd );
        $self->den( $self->d / $gcd ); 
        $self->val( $self->n / $self->d );
    };
    
    sub gcd ($m, $n) {
        return $n if $m == 0;   ## gcd of (0,n) is n
        while ( $n != 0 ) {
            $n > $m and ($m, $n) = ($n, $m);
            my $r = $m - $n * ( int ($m/$n));
            return $n if $r == 0;
            ($m, $n) = ($n, $r);
        }
    }

    sub string ($self) {
        return $self->num . "/" . $self->den;
    };

}



package main;

my $order = shift @ARGV // 7;

my @rats;
for my $den (1..$order) {
    for my $num ( 0..$den) {
        push @rats, new Rat($num, $den);    
    }
}

my %farey = map { $_->string => $_->val } @rats;

say join ' ', sort { $farey{$a} <=> $farey{$b} } keys %farey;