Home > Back-end >  A different result came out during the square of every number digit
A different result came out during the square of every number digit

Time:12-11

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");
} 
  • Related