The weekly challenge 379 - Task 2: Armstrong Number
1 #!/usr/bin/env perl 2 # https://theweeklychallenge.org/blog/perl-weekly-challenge-379/#TASK2 3 # 4 # Task 2: Armstrong Number 5 # ======================== 6 # 7 # You are given two integers, $base and $limit. 8 # 9 # Write a script to find all Armstrong numbers in base $base that are less than 10 # $limit. 11 # 12 ## If raising each of the digits of a nonnegative integer to the power of 13 ## the total number of digits, then taking the sum, equals the original 14 ## number, it is an Armstrong number. 15 # 16 ## Example 1 17 ## 18 ## Input: $base = 10, $limit = 1000 19 ## Output: (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 153, 370, 371, 407) 20 # 21 ## Example 2 22 ## 23 ## Input: $base = 7, $limit = 1000 24 ## Output: (0, 1, 2, 3, 4, 5, 6, 10, 25, 32, 45, 133, 134, 152, 250) 25 # 26 ## Example 3 27 ## 28 ## Input: $base = 16, $limit = 1000 29 ## Output: (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 342, 371, 520, 584, 645) 30 # 31 ############################################################ 32 ## 33 ## discussion 34 ## 35 ############################################################ 36 # 37 # It's not necessarily obvious, but $limit seems to be in base 10 as 38 # per the examples. Also the output is in base 10 as well. 39 # With that in place, we just need to collect all armstrong numbers 40 # until we hit the limit, so a simple loop will do that. 41 # In that loop, we check if the given number is an armstrong number 42 # in the given base: 43 # - rebase to the given base 44 # - take the appropriate power of the digits and sum them up 45 # - if the result equals the original number we can return 1, otherwise 0 46 # The rest is just helper functions to translate between bases. 47 48 use v5.36; 49 50 my @base_digits = (0..9, 'a'..'z'); 51 52 armstrong_numbers(10, 1000); 53 armstrong_numbers(7, 1000); 54 armstrong_numbers(16, 1000); 55 56 sub translated_to_base10($digit) { 57 if($digit =~ m/\d/) { 58 return $digit; 59 } 60 # ord('a') = 97, but we need to start counting at 10 for 'a'. 61 return ord($digit) - 87; 62 } 63 64 sub armstrong_numbers($base, $limit) { 65 say "Input: base = $base, limit = $limit"; 66 my @output = (); 67 foreach my $number (0..$limit) { 68 push @output, $number if is_amstrong_number($number, $base); 69 } 70 say "Output: (" . join(", ", @output) . ")"; 71 } 72 73 sub is_amstrong_number($number, $base) { 74 my $rebased_number = rebase($number, $base); 75 my $len = length($rebased_number); 76 my $r = $rebased_number; 77 my $result = 0; 78 while(length($r)) { 79 $r =~ s/(.)//; 80 my $d = $1; 81 $result += translated_to_base10($d) ** $len; 82 } 83 return $result == $number; 84 } 85 86 sub rebase($number, $base) { 87 return "0" if $number == 0; 88 my $result = ""; 89 while($number > 0) { 90 my $d = $number % $base; 91 $result = $base_digits[$d] . $result; 92 $number = int($number / $base); 93 } 94 return $result; 95 }