diff options
Diffstat (limited to 'challenge-178/bob-lied/perl/ch-1.pl')
| -rw-r--r-- | challenge-178/bob-lied/perl/ch-1.pl | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/challenge-178/bob-lied/perl/ch-1.pl b/challenge-178/bob-lied/perl/ch-1.pl new file mode 100644 index 0000000000..78fa9624ab --- /dev/null +++ b/challenge-178/bob-lied/perl/ch-1.pl @@ -0,0 +1,150 @@ +#!/usr/bin/env perl +# vim:set ts=4 sw=4 sts=4 et ai wm=0 nu: +#============================================================================= +# ch-1.pl Perl Weekly Challenge Week 178 Task 1 Quater-Imaginary Base +#============================================================================= +# Copyright (c) 2023, Bob Lied +#============================================================================= +# Write a script to convert a given number (base 10) to quater-imaginary base +# number and vice-versa. For more informations, please checkout wiki page. +# https://en.wikipedia.org/wiki/Quater-imaginary_base +# For example, +# $number_base_10 = 4 +# $number_quater_imaginary_base = 10300 +# +# The quater-imaginary base is a represention of numbers using the imaginary +# number 2i as the base. Complex numbers are represented with even powers +# as the real part, and odd powers as the imaginary part. +# k (2i)^k +# -- ------ +# 0 1 +# 1 2i +# 2 -4 +# 3 -8i +# 4 16 +# 5 32i +# 6 -64 +# 7 -128i +# 8 256 +# 9 512i +# 10 -1024 +# 11 -2048i +# +# The base 2i is related to the base -4. Every even power of 2i is a +# power of -4. For real numbers, using -4 as a base gives a representation +# where every other digit is 0. +#============================================================================== + +use v5.36; + +use List::MoreUtils qw/part/; + +use Getopt::Long; +my $Verbose = 0; +my $DoTest = 0; + +GetOptions("test" => \$DoTest, "verbose" => \$Verbose); +exit(!runTest()) if $DoTest; + +sub q2d($n) +{ + # Reverse the digits so the indices match the exponents + my @digit = split '', reverse scalar "$n"; + + # Divide into even and odd exponents. The even exponents + # will be the real part; the odd will be imaginary. + my @exponent = part { ($_ % 2) } 0 .. $#digit; + + my @evenPower = @digit[ $exponent[0]->@* ]; + my @oddPower = defined $exponent[1] ? @digit[ $exponent[1]->@* ] : (); + + my ($re, $im) = (0, 0); + for ( my $k = 0; $k <= $#evenPower ; $k++ ) + { + my $sign = ( ($k % 2) ? -1 : 1 ); + my $val = $sign * $evenPower[$k] * (2 ** (2*$k)); + $re += $val; + } + + for ( my $k = 0; $k <= $#oddPower ; $k++ ) + { + my $sign = (($k+1) %2 ? -1 : 1 ); + my $val = $sign * $oddPower[$k] * (2 ** (2*($k+1))); + $im += $val; + } + + return ($im == 0 ) ? "$re" : "$re +${im}i"; +} + +# Only handles real integers +sub d2q($n) +{ + my @digit; + + return 0 if $n == 0; + + # Using base -4 for conversion + while ( $n != 0 ) + { + my $q = int($n / -4); + my $rem = $n - ($q * -4); + $n = $q; + + if ( $rem < 0 ) + { + # Convert negative remainders to positive with + # clock arithmetic, effectively subtract and carry + ($n, $rem) = ($n + 1, $rem + 4) + } + unshift @digit, $rem; + } + # To convert to base 2i, put a zero between each digit + return join("0", @digit); +} + +sub runTest +{ + use Test2::V0; + + is( q2d("1"), 1, "quat to dec 1"); + is( q2d("2"), 2, "quat to dec 2"); + is( q2d("3"), 3, "quat to dec 3"); + is( q2d("10300"), 4, "quat to dec 4"); + is( q2d("10301"), 5, "quat to dec 5"); + is( q2d("10302"), 6, "quat to dec 6"); + is( q2d("10303"), 7, "quat to dec 7"); + is( q2d("10200"), 8, "quat to dec 8"); + is( q2d("10201"), 9, "quat to dec 9"); + is( q2d("10202"), 10, "quat to dec 10"); + is( q2d("10203"), 11, "quat to dec 11"); + is( q2d("10100"), 12, "quat to dec 12"); + is( q2d("10101"), 13, "quat to dec 13"); + is( q2d("10102"), 14, "quat to dec 14"); + is( q2d("10103"), 15, "quat to dec 15"); + is( q2d("10000"), 16, "quat to dec 16"); + + is( d2q(-4), "100", "dec to quat -4"); + is( d2q(-3), "101", "dec to quat -3"); + is( d2q(-2), "102", "dec to quat -2"); + is( d2q(-1), "103", "dec to quat -1"); + is( d2q( 0), "0", "dec to quat 0"); + is( d2q( 1), "1", "dec to quat 1"); + is( d2q( 2), "2", "dec to quat 2"); + is( d2q( 3), "3", "dec to quat 3"); + is( d2q( 4), "10300", "dec to quat 4"); + is( d2q( 5), "10301", "dec to quat 5"); + is( d2q( 6), "10302", "dec to quat 6"); + is( d2q( 7), "10303", "dec to quat 7"); + is( d2q( 8), "10200", "dec to quat 8"); + is( d2q( 9), "10201", "dec to quat 9"); + is( d2q(10), "10202", "dec to quat 10"); + is( d2q(11), "10203", "dec to quat 11"); + is( d2q(12), "10100", "dec to quat 12"); + is( d2q(13), "10101", "dec to quat 13"); + is( d2q(14), "10102", "dec to quat 14"); + is( d2q(15), "10103", "dec to quat 15"); + is( d2q(16), "10000", "dec to quat 16"); + + done_testing; +} + |
