You are given a number
$N >= 10
.Write a script to find out if the given number
$N
is such that sum of squares of all digits is a perfect square. Print1
if it is otherwise0
.
Input: $N = 34 Ouput: 1
Input: $N = 50 Output: 1
Input: $N = 52 Output: 0
The challenge can be split up into two different tasks: summing the squares of the digits, and determining whether the result is a perfect square or not.
Summing the squares of the digits is straightforward.
We offer four different ways to determine whether the sum of the squares
of the digits is a square number. We'll call the sum of the squares
of the digits
First option is take the square root. We cannot simply check whether the
square root is an integer: we're now dealing with floating point numbers.
Instead, we round the square root to the nearest integer, square that,
and compare that with
The advantange of this method is that quick. The disadvantage is that we have to deal with floating point numbers. Which means we may have rounding errors.
The second method we offer is to start counting from
This may sound inefficient, but it's not. If the input has
Instead of counting from
Since
We can precalculate the first 9000 squares. Then, given an
We have the input number in $_
.
First, calculating the sum of the squares of the numbers:
my $sum_of_squares = sum map {$_ * $_} /[1-9]/g;
Note that we ignore 0
s, and the square of 0
is 0
.
$is_square = $sum_of_squares == int (.5 + sqrt $sum_of_squares) ** 2
We'r taking the square root of $sum_of_squares
, rounding it to the
nearest integer, squaring that, and comparing it to $sum_of_squares
.
If equal, $sum_of_squares
is a square, else, it is not.
my $root = 0;
$root ++ while $root * $root < $sum_of_squares;
$is_square = $sum_of_squares == $root * $root;
We simply count upwards as long as the square of our number is less
thatn $sum_of_squares
. Then we check whether we overshot or not:
if we did, it's not a square, else it is.
First, we find a number whose square is larger than $sum_of_squares
:
my $root_min = 0;
my $root_max = 1;
$root_max *= 2 while $root_max * $root_max < $sum_of_squares;
Then we use binary search to zoom into the square root of $sum_of_squares
.
Either we hit it (and hence, the square root of $sum_of_squares
is an
integer, and thus, $sum_of_squares
is a perfect square), or we don't
(and then, $sum_of_squares
is not a perfect square):
while ($root_min < $root_max) {
my $root_mid = int (($root_min + $root_max) / 2);
my $square_mid = $root_mid * $root_mid;
if ($square_mid == $sum_of_squares) {
$is_square = 1;
last;
}
if ($square_mid < $sum_of_squares) {
$root_min = $root_mid + 1;
}
else {
$root_max = $root_mid;
}
}
First, the preprocessing:
my %squares = map {$_ * $_ => 1} 1 .. 9000;
Then it's just a matter of a lookup:
$is_square = $squares {$sum_of_squares};
Find the full program on GitHub.
We have implemenations based on the Taking the square root method in AWK, C, Lua, Node.js, Python and Ruby. And an implemenation based on Binary search in Bash.