Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 273 lines (230 sloc) 7.745 kb
297e783 [t] and [t/spec]
moritz authored
1 use v6;
2 use Test;
3 plan 67;
4
5 {
6 # P31 (**) Determine whether a given integer number is prime.
7 #
8 # Example:
9 # * (is-prime 7)
10 # T
11
12 # Very Naive implementation and
13 # could probably use something like:
14 # subset Divisible::Int of Int where { $_ > 1 };
15 # sub is_prime(Divisible::Int $num) {
16 # but "subset" is not working yet.
17
18 sub is_prime(Int $num) returns Bool {
19
20 # 0 and 1 are not prime by definition
fac7553 [t/spec] A few tweaks to keep the return type checks happy.
jnthn authored
21 return Bool::False if $num < 2;
297e783 [t] and [t/spec]
moritz authored
22
23 # 2 and 3 are
fac7553 [t/spec] A few tweaks to keep the return type checks happy.
jnthn authored
24 return Bool::True if $num < 4;
297e783 [t] and [t/spec]
moritz authored
25
26 # no even number is prime
fac7553 [t/spec] A few tweaks to keep the return type checks happy.
jnthn authored
27 return Bool::False if $num % 2 == 0;
297e783 [t] and [t/spec]
moritz authored
28
29 # let's try what's left
30 my $max=floor(sqrt($num));
31
32 # we could use
199e76c [t/spec] more :by removal
moritz authored
33 # for 3 ... *+2, $max -> $i {
34 # but it doesn't seem to work yet
297e783 [t] and [t/spec]
moritz authored
35 loop (my $i=3; $i <= $max ; $i+=2) {
fac7553 [t/spec] A few tweaks to keep the return type checks happy.
jnthn authored
36 return Bool::False if $num % $i == 0;
297e783 [t] and [t/spec]
moritz authored
37 }
fac7553 [t/spec] A few tweaks to keep the return type checks happy.
jnthn authored
38 return Bool::True;
297e783 [t] and [t/spec]
moritz authored
39 }
40
41 ok !is_prime(0), "We should find that 0 is not prime";
42 ok !is_prime(1), ".. and neither is 1";
43 ok is_prime(2), ".. 2 is prime";
44 ok is_prime(3), ".. 3 is prime";
45 ok !is_prime(4), ".. 4 is not";
46 ok is_prime(5), ".. 5 is prime";
47 ok !is_prime(6), ".. 6 is even, thus not prime";
48 ok !is_prime(15), ".. 15 is product of two primes, but not prime";
49 ok is_prime(2531), ".. 2531 is a larger prime";
50 ok !is_prime(2533), ".. 2533 is not";
51 }
52
53 {
54 # P32 (**) Determine the greatest common divisor of two positive
55 # integer numbers.
56 #
57 # Use Euclid's algorithm.
58 # Example:
59 # * (gcd 36 63)
60 # 9
61
62 # Makes sense to declare types since gcd makes sense only for Ints.
63 # Yet, it should be possible to define it even for commutative rings
64 # other than Integers, so we use a multi sub.
65
3d679db Moritz Lenz some rakudo un/refudging, simplify 99problems-31-to-40.t
moritz authored
66 multi sub gcd(Int $a, Int $b){
297e783 [t] and [t/spec]
moritz authored
67 return $a if $b == 0;
68 return gcd($b,$a % $b);
69 }
70
71 is gcd(36,63), 9, "We should be able to find the gcd of 36 and 63";
72 is gcd(63,36), 9, ".. and viceversa";
73 is gcd(0,5) , 5, '.. and that gcd(0,$x) is $x';
74 is gcd(0,0) , 0, '.. even when $x is 0';
75 }
76
77 {
78 # P33 (*) Determine whether two positive integer numbers are coprime.
79 #
80 # Two numbers are coprime if their greatest common divisor equals 1.
81 # Example:
82 # * (coprime 35 64)
83 # T
84
3d679db Moritz Lenz some rakudo un/refudging, simplify 99problems-31-to-40.t
moritz authored
85 sub coprime(Int $a, Int $b) { $a gcd $b == 1}
297e783 [t] and [t/spec]
moritz authored
86 ok coprime(35,64), "We should be able to tell that 35 and 64 are coprime";
87 ok coprime(64,35), ".. and viceversa";
88 ok !coprime(13,39), ".. but 13 and 39 are not";
89 }
90
91 {
92 sub totient_phi(Int $num) {
3d679db Moritz Lenz some rakudo un/refudging, simplify 99problems-31-to-40.t
moritz authored
93 +grep({$_ gcd $num == 1}, 1 .. $num);
297e783 [t] and [t/spec]
moritz authored
94 }
95
96 # TODO: s/my/constant/
97 my @phi = *,1,1,2,2,4,2,6,4,6,4,10,4,12,6,8,8,16,6,18,8;
98
99 # from Sloane OEIS A000010
100 for 1..20 -> $n {
101 is @phi[$n], totient_phi($n), "totient of $n is @phi[$n]";
102 }
103 }
104
105 {
106 # P35 (**) Determine the prime factors of a given positive integer.
107 #
108 # Construct a flat list containing the prime factors in ascending order.
109 # Example:
110 # * (prime-factors 315)
111 # (3 3 5 7)
112 sub prime_factors($n is copy) {
113 my @factors;
114
115 my $cand = 2;
116 while ($n > 1) {
117 if $n % $cand == 0 {
118 @factors.push($cand);
119 $n /= $cand;
120 }
121 else {
122 $cand++;
123 }
124 }
125 return @factors
126 }
127
128 is prime_factors(315), (3,3,5,7), 'prime factors of 315 are 3,3,5,7';
129 }
130
0836cea Will Coleda nom fudging
coke authored
131 #?DOES 5
297e783 [t] and [t/spec]
moritz authored
132 {
133 # P36 (**) Determine the prime factors of a given positive integer (2).
134 #
135 # Construct a list containing the prime factors and their multiplicity.
136 # Example:
137 # * (prime-factors-mult 315)
138 # ((3 2) (5 1) (7 1))
139 #
140 # Hint: The problem is similar to problem P13.
141
decd043 [t/spec] account for the fact that subs are lexical by default; fudge an...
moritz authored
142 our sub prime_factors_mult(Int $n is copy){
297e783 [t] and [t/spec]
moritz authored
143 return () if $n == 1;
144 my $count = 0;
145 my $cond = 2;
146 return gather {
147 while $n > 1 {
148 if $n % $cond == 0 {
149 $count++;
a4ba5fd [t/spec] correct meaning of infix:<div> and infix:</>. Patch courtesy (m...
moritz authored
150 $n div= $cond;
297e783 [t] and [t/spec]
moritz authored
151 }
152 else {
153 if $count > 0 {
154 take [$cond,$count];
155 $count = 0;
156 }
157 $cond++;
158 }
159 }
160 take [$cond,$count];
161 }
162 }
feebd08 [t/spec]: Update some Nil-related tests for undefined Nil.
pmichaud authored
163 is prime_factors_mult(1),(), "We ignore 1";
164 is prime_factors_mult(2),([2,1]), "We get prime numbers prime";
165 is prime_factors_mult(4),([2,2]), ".. and multiplicity right";
166 is prime_factors_mult(12),([2,2],[3,1]), ".. and products of primes";
167 is prime_factors_mult(315),([3,2],[5,1],[7,1]), ".. and ignore multiplicity 0"
297e783 [t] and [t/spec]
moritz authored
168 }
169
0836cea Will Coleda nom fudging
coke authored
170 #?DOES 20
297e783 [t] and [t/spec]
moritz authored
171 {
172 # P37 (**) Calculate Euler's totient function phi(m) (improved).
173 #
174 # See problem P34 for the definition of Euler's totient function. If the list of
175 # the prime factors of a number m is known in the form of problem P36 then the
176 # function phi(m) can be efficiently calculated as follows: Let ((p1 m1) (p2 m2)
177 # (p3 m3) ...) be the list of prime factors (and their multiplicities) of a given
178 # number m. Then phi(m) can be calculated with the following formula:
179 #
180 # phi(m) = (p1 - 1) * p1 ** (m1 - 1) + (p2 - 1) * p2 ** (m2 - 1) + (p3 - 1) * p3 ** (m3 - 1) + ...
181 #
182 # Note that a ** b stands for the b'th power of a.
183
184 # This made me mad, the above formula is wrong
185 # where it says + it should be *
186 # based on the fact that
187 # phi(prime**m)=prime**(m-1)*(prime-1)
188 # and
189 # some_number=some_prime**n * some_other_prime**m * ....
22fb63e Jonathan Worthington Bring a test inline with spec.
jnthn authored
190
191 our &prime_factors_mult;
192
297e783 [t] and [t/spec]
moritz authored
193 sub phi($n) {
194 my $result=1;
195
196 # XXX - I think there is a way of doing the unpacking + assignment
197 # in one step but don't know how
198
199 for prime_factors_mult($n) -> @a {
200 my ($p,$m) = @a;
201 $result *= $p ** ($m - 1) * ($p - 1);
202 }
203 $result;
204 }
205
206
207 my @phi = *,1,1,2,2,4,2,6,4,6,4,10,4,12,6,8,8,16,6,18,8;
208
209 for 1..20 -> $n {
210 is phi($n), @phi[$n], "totient of $n is {@phi[$n]}";
211 }
212 }
213
214 {
215 # P38 (*) Compare the two methods of calculating Euler's totient function.
216 #
217 # Use the solutions of problems P34 and P37 to compare the algorithms. Take the
218 # number of logical inferences as a measure for efficiency. Try to calculate
219 # phi(10090) as an example.
220
8b5a87e Moritz Lenz reverse order of skip() arguments all over the test suite
moritz authored
221 skip 'No Benchmark module yet', 1
297e783 [t] and [t/spec]
moritz authored
222 }
223
0836cea Will Coleda nom fudging
coke authored
224 #?DOES 2
297e783 [t] and [t/spec]
moritz authored
225 {
226 # P39 (*) A list of prime numbers.
227 #
228 # Given a range of integers by its lower and upper limit, construct a list of all
229 # prime numbers in that range.
230
decd043 [t/spec] account for the fact that subs are lexical by default; fudge an...
moritz authored
231 our sub primes($from, $to) {
297e783 [t] and [t/spec]
moritz authored
232 my @p = (2);
233 for 3..$to -> $x {
234 push @p, $x unless grep { $x % $_ == 0 }, 2..ceiling sqrt $x;
235 }
236 grep { $_ >= $from }, @p;
237 }
238
239 is primes(2,11), (2,3,5,7,11), "a few.";
240 is primes(16,100), (17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97), "a few more.";
241 }
242
0836cea Will Coleda nom fudging
coke authored
243 #?DOES 1
297e783 [t] and [t/spec]
moritz authored
244 {
245 # P40 (**) Goldbach's conjecture.
246 #
247 # Goldbach's conjecture says that every positive even number greater than 2 is
248 # the sum of two prime numbers. Example: 28 = 5 + 23. It is one of the most
249 # famous facts in number theory that has not been proved to be correct in the
250 # general case. It has been numerically confirmed up to very large numbers (much
251 # larger than we can go with our Prolog system). Write a predicate to find the
252 # two prime numbers that sum up to a given even integer.
253 #
254 # Example:
255 # * (goldbach 28)
256 # (5 23)
257
22fb63e Jonathan Worthington Bring a test inline with spec.
jnthn authored
258 our &primes;
259
297e783 [t] and [t/spec]
moritz authored
260 sub goldbach($n) {
261 my @p = primes(1, $n-1);
262 for @p -> $x {
263 for @p -> $y {
264 return ($x,$y) if $x+$y == $n;
265 }
266 }
267 }
268
269 is goldbach(28), (5, 23), "Goldbach works.";
270 }
7f29bc5 [t/spec] Add vim: lines everywhere.
kyle authored
271
272 # vim: ft=perl6
Something went wrong with that request. Please try again.