2009-05-26 2 views
8

Esiste un modo sicuro per aggiungere una cifra alla fine di un intero senza convertirla in una stringa e senza utilizzare le stringhe?Aggiungi cifra a un int senza convertire in stringa?

Ho provato a google la risposta per questo e la maggior parte delle soluzioni ha suggerito di convertirlo in una stringa e utilizzando stringstreams ma vorrei mantenerlo come un numero intero per garantire l'integrità dei dati ed evitare la conversione dei tipi.
Ho anche letto una soluzione che suggeriva di moltiplicare l'int per 10 e quindi di aggiungere la cifra, tuttavia ciò potrebbe causare un overflow di numeri interi.
È sicuro farlo o esiste un metodo migliore per farlo? E se lo faccio moltiplicare per 10 e aggiungere la soluzione di cifre, quali precauzioni dovrei prendere?

risposta

25

La soluzione migliore è la moltiplicazione per 10 e l'aggiunta del valore. Si potrebbe fare a naive check in questo modo:

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

eccellente! Grazie mille! – nmuntz

+0

Il controllo di overflow è sbagliato. Ad esempio, 4772185889 - 2^32 = 477218593, che è maggiore di 477218588. –

+0

Sono d'accordo, mi sono collegato a dove è possibile ottenere un'implementazione meno che ingenuo. – user7116

3

per evitare overflow:

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

Al posto di MAX_INT, è possibile utilizzare std::numeric_limits<typeof(value)>::max() o simili, per supportare i tipi diversi 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

Ecco un un'attuazione migliore e più a prova di proiettile di quello che è stato accettato come una risposta che è anche veloce:

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

Si dovrebbe anche essere in grado di fare questo in una funzione inline. Il controllo di troppopieno sarà quasi sempre cortocircuito dopo il primo confronto. La clausola dopo il && è semplicemente così è possibile (nel caso di un 32 bit, numero intero di complemento) aggiungere 5 alla fine di 429496729, ma non 6.