Append digit to an int without converting to string?

14,669

Solution 1

Your best bet is the multiplication by 10 and addition of the value. You could do a naive check like so:

assert(digit >= 0 && digit < 10);
newValue = (oldValue * 10) + digit;
if (newValue < oldValue)
{
    // overflow
}

Solution 2

To prevent overflow:

if ((0 <= value) && (value <= ((MAX_INT - 9) / 10))) {
    return (value * 10) + digit;
}

In place of MAX_INT, you could use std::numeric_limits<typeof(value)>::max() or similar, to support types other than int.

Solution 3

  assert(digit >= 0 && digit < 10);
  newvalue = 10 * oldvalue;
  if (oldvalue < 0 ) {
    newvalue -= digit;
  } else {
    newvalue += digit;
  }

  // check for overflow SGN(oldvalue) == 0 || SGN(newvalue) == SGN(oldvalue)

Solution 4

Here is a better and more bulletproof implementation than the one that was accepted as an answer that is also fast:

#include <climits>
#include <cassert>

unsigned int add_digit(unsigned int val, unsigned int digit)
{
   // These should be computed at compile time and never even be given a memory location
   static const unsigned int max_no_overflow = (UINT_MAX - 9) / 10U;
   static const unsigned int max_maybe_overflow = UINT_MAX / 10U;
   static const unsigned int last_digit = UINT_MAX % 10;

   assert(digit >= 0 && digit < 10);
   if ((val > max_no_overflow) && ((val > max_maybe_overflow) || (digit > last_digit))) {
      // handle overflow
   } else {
      return val * 10 + digit;
   }
   assert(false);
}

You should also be able to make this into an inline function. The overflow check will almost always short circuit after the first comparison. The clause after the && is simply so you can (in the case of a 32 bit, two's complement integer) add 5 to the end of 429496729, but not 6.

Share:
14,669
nmuntz
Author by

nmuntz

Updated on June 23, 2022

Comments

  • nmuntz
    nmuntz almost 2 years

    Is there a safe way of adding a digit at the end of an integer without converting it to a string and without using stringstreams ?

    I tried to google the answer for this and most solutions suggested converting it to a string and using stringstreams but I would like to keep it as an integer to ensure data integrity and to avoid converting types.
    I also read a solution which suggested to multiply the int by 10 and then adding the digit, however this might cause an integer overflow.
    Is this safe to do or is there a better method for doing this? And if I do this multiply by 10 and add the digits solution, what precautions should I take?

  • Steve Jessop
    Steve Jessop almost 15 years
    The overflow check is wrong. For example, 4772185889 - 2^32 = 477218593, which is greater than 477218588.
  • Sam
    Sam almost 15 years
    I agree, I linked to where you can get a less than naive implementation.
  • Omnifarious
    Omnifarious about 14 years
    I put in an answer later that has a very fast overflow check that always works.