2009-05-26 18 views
8

¿Existe una forma segura de agregar un dígito al final de un número entero sin convertirlo en una cadena y sin utilizar cadenas de caracteres?¿Agregar un dígito a un int sin convertirlo a una cadena?

Intenté google la respuesta para esto y la mayoría de las soluciones sugirieron convertirlo en una cadena y usar cadenas de caracteres, pero me gustaría mantenerlo como un número entero para garantizar la integridad de los datos y evitar la conversión de tipos.
También leí una solución que sugería multiplicar el int por 10 y luego agregar el dígito, sin embargo, esto podría causar un desbordamiento de enteros.
¿Es seguro o hay un método mejor para hacer esto? Y si hago esto multiplicar por 10 y agregar la solución de dígitos, ¿qué precauciones debo tomar?

Respuesta

25

Su mejor apuesta es la multiplicación por 10 y la adición del valor. Usted podría hacer a naive check así:

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

¡excelente! ¡muchas gracias! – nmuntz

+0

La verificación de desbordamiento es incorrecta. Por ejemplo, 4772185889 - 2^32 = 477218593, que es mayor que 477218588. –

+0

Acepto, me he vinculado a donde puede obtener una implementación menos ingenua. – user7116

3

Para evitar desbordamiento:

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

En lugar de MAX_INT, podría utilizar std::numeric_limits<typeof(value)>::max() o similar, para soportar tipos distintos de int.

2
 
    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) 
2

Aquí es una aplicación mejor y más a prueba de balas que el que fue aceptado como una respuesta que también es rápido:

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

También debe ser capaz de hacer esto en una función en línea. La verificación de desbordamiento casi siempre provocará un cortocircuito después de la primera comparación. La cláusula después de && es simplemente para que pueda (en el caso de un entero complementario de dos y 32 bits) agregar 5 al final de 429496729, pero no 6.