Добавить цифру в 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.