Добавить цифру в int без преобразования в строку? - PullRequest
8 голосов
/ 26 мая 2009

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

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

Ответы [ 4 ]

25 голосов
/ 26 мая 2009

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

assert(digit >= 0 && digit < 10);
newValue = (oldValue * 10) + digit;
if (newValue < oldValue)
{
    // overflow
}
3 голосов
/ 27 мая 2009

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

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

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

2 голосов
/ 28 января 2010

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

#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-битного целого числа с дополнением до двух) добавить 5 к концу 429496729, но не 6.

2 голосов
/ 27 мая 2009
  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)
...