I'm trying to square every digit of a number, concatenate them and return the result as an integer.
For example, if I run 9191 through the function, 811181 will come out, because 9^2 is 81 and 1^2 is 1.
I made a function (don't even know if it's the most optimal, I'm quite new with the programming) so that the number gets converted into a string, then I loop through it, convert the single digit from a char back to a number and make the square of it. Then I save the new result in the form of a string, and concatenate it to another string that will be the final result.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 128
unsigned long long square_digits (unsigned n)
{
char n_str[MAX];
char c_str[MAX];
char s_result[MAX];
unsigned long long converted, result;
int i, len;
sprintf(n_str, "%u", n);
len = strlen(n_str);
s_result[0] = '\0';
for (i = 0; i < len; i)
{
converted = n_str[i] - '0';
converted = converted * converted;
sprintf(c_str, "%llu", converted);
strcat(s_result, c_str);
}
result = strtol(s_result, NULL, 10);
return result;
}
The tests are made through the following sequence of numbers:
unsigned long long square_digits (unsigned n);
#define do_test(n, expected) \
do { \
unsigned long long actual = square_digits(n); \
cr_assert_eq(actual, expected, "for n = %u, expected %llu, but got %llu", n, expected, actual);\
} while (false)
Test(test_suite, sample_tests)
{
do_test( 3212u, 9414ull);
do_test( 2112u, 4114ull);
do_test( 0u, 0ull);
do_test( 999u, 818181ull);
do_test( 10001u, 10001ull);
do_test(3210987654u, 9410816449362516ull);
do_test(3999999999u, 9818181818181818181ull); // :p
do_test( UINT_MAX, 164811681364948125ull);
}
First 6 tests are passed correctly, but then I got an unexpected result (the one with the ":p" comment).
sample_tests
Test Passed
Test Passed
Test Passed
Test Passed
Test Passed
Test Passed
for n = 3999999999, expected 9818181818181818181, but got 9223372036854775807
What is happening and how can I fix that? Is there another way to make this work?
CodePudding user response:
9818181818181818181
is a 64-bit unsigned number with its most significant bit set.
OP's strtol(s_result, NULL, 10)
is for signed conversion and 9818181818181818181
is outside its range. strtol()
did the best it could and returned LONG_MAX
, 9223372036854775807 or 0x7FFF_FFFF_FFFF_FFFF.
Use a matching conversion function: strtoull()
.
unsigned long long result;
...
// result = strtol(s_result, NULL, 10);
result = strtoull(s_result, NULL, 10);
More advanced code would check the conversion:
char *endptr;
errno = 0;
result = strtoull(s_result, &endptr, 10);
if (s_result == endptr || errno) {
puts("Trouble in conversion");
}