2009-05-26 11 views
8

Czy istnieje bezpieczny sposób dodawania cyfry na końcu liczby całkowitej bez przekształcania jej na ciąg i bez używania łańcuchów?Dołącz cyfrę do int bez konwersji na ciąg?

Próbowałem odpowiedzieć na to pytanie w języku angielskim i większość rozwiązań sugerowała konwersję na ciąg znaków i użycie łańcuchów, ale chciałbym zachować go jako liczbę całkowitą, aby zapewnić integralność danych i uniknąć konwersji typów.
Przeczytałem również rozwiązanie, które sugerowało pomnożenie int przez 10, a następnie dodanie cyfry, jednak może to spowodować przepełnienie liczby całkowitej.
Czy można to bezpiecznie zrobić, czy jest na to lepsza metoda? A jeśli zrobię to pomnożyć przez 10 i dodać rozwiązanie cyfry, jakie środki ostrożności powinienem podjąć?

Odpowiedz

25

Twój najlepszy zakład to pomnożenie przez 10 i dodanie wartości. Można zrobić a naive check tak:

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

doskonała! Dziękuję Ci bardzo! – nmuntz

+0

Kontrola przepełnienia jest nieprawidłowa. Na przykład 4772185889 - 2^32 = 477218593, który jest większy niż 477218588. –

+0

Zgadzam się, połączyłem się z tym, gdzie można uzyskać mniej niż naiwną implementację. – user7116

3

Aby uniknąć przepełnienia:

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

W miejsce MAX_INT, można użyć std::numeric_limits<typeof(value)>::max() lub podobny do wsparcia rodzajów innych niż 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

Tutaj jest lepszym i bardziej kuloodporny realizacja niż ta, która została przyjęta jako odpowiedź, która jest również szybki:

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

Należy także być w stanie dokonać tego w funkcji inline. Kontrola przepełnienia prawie zawsze zwiąże po pierwszym porównaniu. Klauzula po && jest po prostu taka, że ​​możesz (w przypadku 32-bitowej liczby całkowitej drugiej) dodać 5 do końca 429496729, ale nie 6.