Добавить цифру в int без преобразования в строку?

есть ли безопасный способ добавить цифру в конце целого числа без преобразования ее в строку и без использования stringstreams ?

Я попытался google ответ для этого, и большинство решений предложили преобразовать его в строку и использовать stringstreams, но я хотел бы сохранить его как целое число, чтобы обеспечить целостность данных и избежать преобразования типов.
Я также прочитал решение, которое предложило умножить int на 10, а затем добавить цифру, однако это может вызвать переполнение целого числа.
Безопасно ли это делать или есть лучший способ сделать это? И если я сделаю это умножить на 10 и добавить решение цифры, какие меры предосторожности я должен принять?

4 ответов


ваш лучший выбор-умножение на 10 и добавление значения. Вы могли бы сделать наивный проверки вот так:

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

для предотвращения перелива:

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

вместо MAX_INT вы можете использовать std::numeric_limits<typeof(value)>::max() или подобный, чтобы поддержать типы int.


  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)

вот лучшая и более пуленепробиваемая реализация, чем та, которая была принята в качестве ответа, который также быстр:

#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);
}

вы также должны иметь возможность сделать это встроенной функцией. Проверка переполнения почти всегда будет короткое замыкание после первого сравнения. Предложение после && просто, чтобы вы могли (в случае 32-битного целого числа дополнения two) добавить 5 в конец 429496729, но не 6.