Perl Weekly Challenge 120.
My solutions (task 1 and task 2) to the The Weekly Challenge - 120.
Task 1: Swap Odd/Even bits
Submitted by: Mohammad S Anwar
You are given a positive integer $N less than or equal to 255.
Write a script to swap the odd positioned bit with even
positioned bit and print the decimal equivalent of the new
binary representation.
Example
Input: $N = 101
Output: 154
Binary representation of the given number is 01 10 01 01.
The new binary representation after the odd/even swap is 10 01
10 10.
The decimal equivalent of 10011010 is 154.
Input: $N = 18
Output: 33
Binary representation of the given number is 00 01 00 10.
The new binary representation after the odd/even swap is 00 10
00 01.
The decimal equivalent of 100001 is 33.
I can get the even and odd bits by applying the &
operator
with masks that have only even or odd bits on: 10101010=>170
is an 8 bit binary number with all odd bits set (counting
right to left from 0) while 01010101=>85
has all even bits
set. Then I can shift the odd bits left and the even bits right and combine
them with |
to get the result. The program is a one liner:
perl -E 'say "Input: $_, Output: ",\
((($_&170)>>1) |(($_&85)<<1)) for @ARGV' 101 18
Results:
Input: 101, Output: 154
Input: 18, Output: 33
The full version:
# Perl weekly challenge 120
# Task 1: Swap odd/even bits
#
# See https://wlmb.github.io/2021/07/07/PWC120/#task-1-swap-oddeven-bits
use strict;
use warnings;
use v5.12;
use List::Util qw(all);
my $odd=170; # 10101010
my $even=85; # 01010101
say "Input: $_, Output: ",
0<=$_<=255?((($_&$odd)>>1) |(($_&$even)<<1)):"Invalid"
for @ARGV;
Example:
./ch-1.pl 101 18 300
Results:
Input: 101, Output: 154
Input: 18, Output: 33
Input: 300, Output: Invalid
Task 2: Clock Angle
Submitted by: Mohammad S Anwar
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.
HINT: A analog clock is divided up into 12 sectors. One sector
represents 30 degree (360/12 = 30).
Example
Input: $T = '03:10'
Output: 35 degree
The distance between the 2 and the 3 on the clock is 30
degree.
For the 10 minutes i.e. 1/6 of an hour that have passed.
The hour hand has also moved 1/6 of the distance between the 3
and the 4, which adds 5 degree (1/6 of 30).
The total measure of the angle is 35 degree.
Input: $T = '04:00'
Output: 120 degree
The angle moved by the minutes hand is proportional to the minutes. The angle moved by the hours hand is proportional to the hour+the fraction of hour corresponding to the minutes. So the solution to the problem is simply obtained using modular arithmetic. If the angle is too large, I substract it from a full turn. This allows a one liner solution.
perl -E 'for(@ARGV){$_=~m/^(\d?\d):(\d\d)$/ or next; $a=(30*($1+$2/60)-$2*6)%360;\
say "Input: $_, Output: ", $a>180?360-$a:$a;}' 03:10 04:00
Results:
Input: 03:10, Output; 35
Input: 04:00, Output; 120
The full version
# Perl weekly challenge 120
# Task 2: Clock angle
#
# See https://wlmb.github.io/2021/07/07/PWC120/#task-2-clock-angle
use strict;
use warnings;
use v5.12;
for(@ARGV){
say "Wrong format: $_", next
unless $_=~m/^(\d?\d):(\d\d)$/
&& 0<=$1<=24 && 0<=$1<60; # <24?
my $angle=(30*($1+$2/60)-$2*6)%360;
$angle=360-$angle if $angle>180;
say "Input: $_, Output: $angle";
}
Examples:
./ch-2.pl 03:10 04:00
Results:
Input: 03:10, Output: 35
Input: 04:00, Output: 120
Other examples:
./ch-2.pl 15:10 16:00 16:40
Results:
Input: 15:10, Output: 35
Input: 16:00, Output: 120
Input: 16:40, Output: 100