diff options
| author | drbaggy <js5@sanger.ac.uk> | 2021-07-05 12:50:38 +0100 |
|---|---|---|
| committer | drbaggy <js5@sanger.ac.uk> | 2021-07-05 12:50:38 +0100 |
| commit | 6a34fbf8bf1d68a78200d7c0752ad330aa96b820 (patch) | |
| tree | b11a980aad0ed57c16af427bf06c93ff6298574c | |
| parent | a8590c122cd7cafb611a27ebecf933aa76b1a494 (diff) | |
| parent | 127da3751b077475421c1624462d7214cff97d40 (diff) | |
| download | perlweeklychallenge-club-6a34fbf8bf1d68a78200d7c0752ad330aa96b820.tar.gz perlweeklychallenge-club-6a34fbf8bf1d68a78200d7c0752ad330aa96b820.tar.bz2 perlweeklychallenge-club-6a34fbf8bf1d68a78200d7c0752ad330aa96b820.zip | |
gitpushMerge branch 'master' of github.com:drbaggy/perlweeklychallenge-club
| -rw-r--r-- | challenge-120/james-smith/README.md | 41 |
1 files changed, 41 insertions, 0 deletions
diff --git a/challenge-120/james-smith/README.md b/challenge-120/james-smith/README.md index a45bcb3af2..c87399295c 100644 --- a/challenge-120/james-smith/README.md +++ b/challenge-120/james-smith/README.md @@ -18,11 +18,52 @@ https://github.com/drbaggy/perlweeklychallenge-club/tree/master/challenge-119/ja ## The solution +This is very similar to last weeks challenge - but instead of swapping bits 4-7 with bits 0-3 this time we are swapping even bits with odd bits - so the solution is similar... + +The even bits are found by bit-wise *and*ing the number with `0b01010101` 0r `0x55` (`85` decimal) and the odd bits are found by bit-wise anding with `0b10101010` or `0xaa` (`170` decimal). We then switch them by multiplying or dividing by 2 {which we do with the bit shift operators `<<` & `>>`}. We just have to add the two values together - as we know the bits don't overlap we can use `|` rather than `+`. + +```perl +sub switch_bits { + ($_[0]&0xaa)>>1 | ($_[0]&0x55)<<1; +} +``` + # Task 2 - Clock Angle ***You are given time `$T` in the format `hh:mm`. Write a script to find the smaller angle formed by the hands of an analog clock at a given time.*** ## The solution +Given a time we can compute the position of the hour hand as `$hr*30+$min/2` and the minute hand as `$min*6`. + +We can then get the angle between the two as: `($hr*60+$min-$min*12)/2` + +We want to reduce this modulo `360` to map the value to the range `0` - `360`. **BUT** we note that `$min` may be odd and the value of the angle may therefore may not be a whole number. To get round this we perform the modulus (by `720`) before the divide by `2`. + +This gives us a number between `0` and `360`. But we need a number between `0` and `180`. To map the range `180` - `360` we can either use an IF OR we can note that if we +do `abs(angle - 180)` we get the complementary angle. So we just subtract this from `180` giving the method below... + +```perl +sub clock_angle_1_liner { + 180-abs((60*(substr$_[0],0,2)-11*substr$_[0],3)%720/2-180); +} +``` + +Compared to this (perhaps slightly more readable) method there is about a 60% performance gain [avoiding variables!] +```perl +sub clock_angle { + my($h,$m) = split /:/,shift; + my $t = abs($h*60-$m*11)%720/2; + return $t > 180 ? 360-$t : $t; +} +``` + +**Note** We can gain more speed (90% faster than "simple" method and about 15% faster than the 1-liner) by removing the first `substr` but to do so we need to disable `numeric` warnings - `no warnings qw(numeric)`. +```perl +sub clock_angle_fast { + 180-abs((60*$_[0]-11*substr$_[0],3)%720/2-180); +} +``` +(Without disabling warnings this gives `Argument "04:00" isn't numeric in multiplication (*) at ..` errors) |
