views:

312

answers:

4

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?

+23  A: 

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
}
sixlettervariables
excellent! thank you very much!
nmuntz
The overflow check is wrong. For example, 4772185889 - 2^32 = 477218593, which is greater than 477218588.
Steve Jessop
I agree, I linked to where you can get a less than naive implementation.
sixlettervariables
+1 for linking to CERT.
mskfisher
I put in an answer later that has a very fast overflow check that always works.
Omnifarious
+3  A: 

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.

Steve Jessop
+1  A: 
Jim
+1  A: 

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.

Omnifarious