aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordrbaggy <js5@sanger.ac.uk>2021-11-16 10:48:11 +0000
committerdrbaggy <js5@sanger.ac.uk>2021-11-16 10:48:11 +0000
commitbf9b3ce83d660eb72c996774e08c33778211f374 (patch)
tree8fed31b3cb4ddce26e2f0e4eb223f37093dd5b30
parentbf73c0e75e253966ca632ff8d5252a4faed944d7 (diff)
downloadperlweeklychallenge-club-bf9b3ce83d660eb72c996774e08c33778211f374.tar.gz
perlweeklychallenge-club-bf9b3ce83d660eb72c996774e08c33778211f374.tar.bz2
perlweeklychallenge-club-bf9b3ce83d660eb72c996774e08c33778211f374.zip
updated readme
-rw-r--r--challenge-139/james-smith/README.md86
1 files changed, 86 insertions, 0 deletions
diff --git a/challenge-139/james-smith/README.md b/challenge-139/james-smith/README.md
index ae4b2357ff..c648fd5c73 100644
--- a/challenge-139/james-smith/README.md
+++ b/challenge-139/james-smith/README.md
@@ -18,9 +18,95 @@ https://github.com/drbaggy/perlweeklychallenge-club/tree/master/challenge-139/ja
## The solution
+This challenge is relatively easy - to see if the list of numbers if monotonically increasing we just have to check that each entry is bigger than the one before.
+
+* We start by shifting the first number of the list passeda (this is the *previous number*);
+* The loop through the rest comparing the current number against the previous number.
+ * If the number is less than the previous number we return `0`;
+ * Otherwise we set previous number `$p` to the current number and continue
+* If we get to the end of the list then the list is sorted and we return `1`.
+
+```
+sub in_order {
+ my $p = shift;
+ ($p>$_) ? (return 0) : ($p=$_) for @_;
+ return 1;
+}
+```
+
+**Notes:**
+
+* We can rewrite the `if( $x ) { y } else { z }` and `($x) ? (y) : (z)`. Why is this useful - well we can then use the brace less postfix `for` for the loop rather than having to use braces. This means the loop becomes 1 line, rather than the longer 7 line version using K&R braces. If you don't cuddle your braces it is even longer!
+
+```
+ for (@_) {
+ if( $p>$_ ) {
+ return 0;
+ } else {
+ $p = $_;
+ }
+ }
+```
+
+Admittedly there is an intermediate version... That uses the exit early approach..
+
+```
+ for (@_) {
+ return 0 if $p>$_;
+ $p = $_;
+ }
+```
+that has only 4-lines.
+
# Task 2 - Long Primes
***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.***
## Solution
+Now this challenge is not so easy - but those of us who have been working on the challenges for more than 6 months would have already worked out parts of fractions which are recursive. There were many solutions for this - if you didn't do the challenge.
+
+You can see mine at:
+
+https://github.com/drbaggy/perlweeklychallenge-club/blob/master/challenge-106/james-smith/perl/ch-2.pl
+
+Now we don't require the actual part of the number repeats which makes the function simpler, and we know explicitly that the numerator is going to be 1.
+
+This gives us the function below to get the length of the recurring sequence.
+
+```
+sub rec_len {
+ my( $D, $N, $s ) = ( shift, 1, '' );
+ ($s,$N) = $D>$N ? ($s.0, $N.0)
+ : ($s.int($N/$D),($N%$D).0) for 0 .. 2*$D;
+ $s =~ m{(\d+?)\1+$};
+ length $1;
+}
+```
+
+* We compute twice the number of digits than the denominator, we generate this as a string but using long-division to compute each digit.
+
+* We then see if there is any repeating sequence (tied to the end of the sting we generate). We then get the length of this recurrent string.
+
+So now we have this function we can look at computing the long primes. We know that `1/2` doesn't recur so we can rule this out - that means we are only considering odd primes.
+
+Therefore we loop through all the odd numbers checking to see if the number is a prime, if it is we then check for the property that the recurring sequence has `$p-1` digits.
+
+```
+O: for( my $p=3; @long_primes<$N; $p+=2 ) {
+ ($p % $_) || (next O) for @primes;
+ push @primes, $p;
+ push @long_primes, $p if $p - rec_len($p) == 1;
+}
+```
+We will now break this down.
+* The `for` line is obvious - repeat increasing `$p` by two until we have sufficient long primes.
+* The next line loops through all current known primes to see if they are factor of `$p` - if yes skips to the next outer loop.
+ * We use `next O` to jump out of the inner `for` loop, and to the start of the next outer `for` loop - labelled `O`.
+ * We again use a trick to flatten the loop with a conditional: `($p % $_) || (next O)` if the first part is true the "or" `||` is true, so we don't evaluate the second part. But it `$_` is a factor of `$p` the left hand side is `0` (false) and so we need to evaluate it to see if the right hand side is true - and in the evaluation - skips to the start of the loop by executing `next O`.
+* We know it has no known prime factors in line 3 so we add it to the list of primes.
+* Then we use our `rec_len` function to see if the number is in fact a long prime.
+
+
+
+