2009-05-26 4 views
8

Existe-t-il un moyen sûr d'ajouter un chiffre à la fin d'un entier sans le convertir en chaîne et sans utiliser de chaînes?Ajouter un chiffre à un int sans le convertir en chaîne?

J'ai essayé de google la réponse pour ceci et la plupart des solutions suggérées la convertissant en chaîne et utilisant des strings mais je voudrais le garder comme un entier pour assurer l'intégrité de données et pour éviter des types de conversion.
J'ai aussi lu une solution qui suggérait de multiplier l'int par 10 puis d'ajouter le chiffre, mais cela pourrait provoquer un débordement d'entier.
Est-ce sûr à faire ou existe-t-il une meilleure méthode pour cela? Et si je fais cela multiplier par 10 et ajouter la solution numérique, quelles précautions dois-je prendre?

Répondre

25

Votre meilleur pari est la multiplication par 10 et l'addition de la valeur. Vous pouvez faire a naive check comme ceci:

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

excellent! Merci beaucoup! – nmuntz

+0

Le contrôle de débordement est incorrect. Par exemple, 4772185889 - 2^32 = 477218593, ce qui est supérieur à 477218588. –

+0

Je suis d'accord, j'ai lié à où vous pouvez obtenir une implémentation moins que naïf. – user7116

3

Pour éviter tout débordement:

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

Au lieu de MAX_INT, vous pouvez utiliser std::numeric_limits<typeof(value)>::max() ou similaire, pour soutenir les types autres que 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

Voici une meilleure et plus l'épreuve des balles mise en œuvre que celle qui a été accepté comme une réponse qui est aussi rapide:

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

Vous devez également être en mesure de faire cela en une fonction en ligne. Le contrôle de débordement sera presque toujours court-circuité après la première comparaison. La clause après le && est simplement que vous pouvez (dans le cas d'un entier de 32 bits, complément de deux) ajouter 5 à la fin de 429496729, mais pas 6.