22 March 2024  Challenge 261 
Bits, Digits and Numbers
Task 1: Element Digit Sum
Submitted by: Mohammad Sajid Anwar
You are given an array of integers, @ints
.
Write a script to evaluate the absolute difference between element and digit sum of the given array.
Example 1
Input: @ints = (1,2,3,45)
Output: 36
Element Sum: 1 + 2 + 3 + 45 = 51
Digit Sum: 1 + 2 + 3 + 4 + 5 = 15
Absolute Difference:  51  15  = 36
Example 2
Input: @ints = (1,12,3)
Output: 9
Element Sum: 1 + 12 + 3 = 16
Digit Sum: 1 + 1 + 2 + 3 = 7
Absolute Difference:  16  7  = 9
Example 3
Input: @ints = (1,2,3,4)
Output: 0
Element Sum: 1 + 2 + 3 + 4 = 10
Digit Sum: 1 + 2 + 3 + 4 = 10
Absolute Difference:  10  10  = 0
Example 4
Input: @ints = (236, 416, 336, 350)
Output: 1296
Solution
The task will be generalized to an arbitrary base \(b > 1\). For any nonnegative integer we have
\[n = \sum_{i=0}^l d_i b^i \ge \sum_{i=0}^l d_i\]and thus there is no need to take the absolute value of the difference between a number and the sum of its digits.
Using some functions from Math::Prime::Util
,
the task may be solved in a single statement:
use strict;
use warnings;
use Math::Prime::Util qw(vecreduce vecsum todigits);
sub eds {
my $base = shift;
vecreduce {$a + $b  vecsum todigits $b, $base} 0, @_;
}
See the full solution.
Task 2: Multiply by Two
Submitted by: Mohammad Sajid Anwar
You are given an array of integers, @ints
and an integer $start
.
Write a script to do the followings:
a) Look for $start
in the array @ints
, if found multiply the number by 2
b) If not found stop the process otherwise repeat
In the end return the final value.
Example 1
Input: @ints = (5,3,6,1,12) and $start = 3
Output: 24
Step 1: 3 is in the array so 3 x 2 = 6
Step 2: 6 is in the array so 6 x 2 = 12
Step 3: 12 is in the array so 12 x 2 = 24
24 is not found in the array so return 24.
Example 2
Input: @ints = (1,2,4,3) and $start = 1
Output: 8
Step 1: 1 is in the array so 1 x 2 = 2
Step 2: 2 is in the array so 2 x 2 = 4
Step 3: 4 is in the array so 4 x 2 = 8
8 is not found in the array so return 8.
Example 3
Input: @ints = (5,6,7) and $start = 2
Output: 2
2 is not found in the array so return 2.
Solution
The task can be solved in a single pass through the list as we know the target values beforehand: \(\mathit{start}\,\cdot\,2^i\). Actually, we need to know which is the smallest of the target values that is missing from the list. For this end we define a bit vector of target indicators that is allzero initially. For every target value we encounter, the corresponding indicator bit will be set. Finally, the least significant bit that is not set leads to the requested result.
The core of this implementation is some bit fiddling. In the following “\(\sim\)” is the bitwise NOT and “\(\&\)” the bitwise AND operation.
Determine if an integer is a power of two
\(n\,\&\,(n  1) = 0 \quad \Leftrightarrow \quad n = 0 \text{ or } n = 2^k\)
Why does this work?

Suppose \(n\) is a power of two.
 Its binary representation is a single onebit followed by zero or more zerobits.
 Subtracting one turns the onebit to zero and the following zerobits (if any) to one.
 There is not a single bit set in both \(n\) and \(n1\) and thus \(n\,\&\,(n  1) = 0\).
n: 0 … 0 1 0 … 0 n1: 0 … 0 0 1 … 1 n&(n1): 0 … 0 0 0 … 0 
Suppose \(n\,\&\,(n  1) = 0\). Let \(n > 0\).
 \(n\) has a least significant onebit, followed by zero or more zerobits.
 Subtracting one from \(n\) turns the least significant onebit to zero and the following (if any) zerobits to one. None of the bits preceding the least significant onebit changes.
 As \(n\,\&\,(n  1) = 0\), all preceding bits must be zero. Therefore the least significant bit in \(n\) is the only onebit in \(n\) leading to \(n = 2^k\).
n: … x … 1 0 … 0 n1: … x … 0 1 … 1 n&(n1): … x … 0 0 … 0 n: … 0 … 1 0 … 0
Determine the value of the least significant bit that is zero:
\(v = (n + 1)\,\&\,\sim n\)
Why does this work?

\(n\) is represented as a sequence of arbitrary bits, followed by a zerobit and zero or more onebits.
 \(\sim n\) has the arbitrary bits flipped, followed by a onebit and zero or more zerobits

\(n + 1\) has the zerobit flipped to one, the following (if any) onebits flipped to zero and the leading arbitrary bits remain unchanged.

Taking into account that \(x \& \neg x = 0\), we find \((n + 1)\,\&\,\sim n = 2^k\)
n: … x … 0 1 … 1 ~n: … ~x … 1 0 … 0 n+1: … x … 1 0 … 0 (n + 1)&~n: … 0 … 1 0 … 0
Implementation
The task can be solved in a single run of some simple steps:
 reject values not divisible by
$start
 divide values by
$start
 collect the corresponding bit for powers of two
Finally find the value corresponding to the least significant zerobit in the collected powers.
This gives the required factor for $start
.
The false positive poweroftwo test for zero does not harm because zero does not account for the collected powers.
use strict;
use warnings;
use experimental 'prototypes';
sub mb2 ($start, @ints) {
my $p = 0;
for my $i (@ints) {
next if $i % $start;
my $c = $i / $start;
$p = $c unless $c & ($c  1);
}
$start * (($p + 1) & ~$p);
}
See the full solution.
If you have a question about this post or if you like to comment on it, feel free to open an issue in my github repository.