10 Stimmen

Anhängen von Ziffern an einen int ohne Konvertierung in einen String?

Gibt es eine sichere Möglichkeit, eine Ziffer am Ende einer Ganzzahl hinzuzufügen, ohne sie in eine Zeichenkette umzuwandeln und ohne Stringstreams zu verwenden?

Ich habe versucht, die Antwort für dieses zu googeln und die meisten Lösungen schlug vor, es in eine Zeichenfolge zu konvertieren und Stringstreams zu verwenden, aber ich möchte es als Ganzzahl halten, um die Datenintegrität zu gewährleisten und die Umwandlung von Typen zu vermeiden.
Ich habe auch eine Lösung gelesen, die vorschlug, den int mit 10 zu multiplizieren und dann die Ziffer zu addieren, was jedoch zu einem Integer-Überlauf führen könnte.
Ist dies sicher, oder gibt es eine bessere Methode dafür? Und wenn ich diese Lösung mit 10 multipliziere und die Ziffern addiere, welche Vorsichtsmaßnahmen sollte ich treffen?

26voto

user7116 Punkte 61589

Das Beste ist die Multiplikation mit 10 und die Addition des Wertes. Sie könnten tun eine naive Prüfung etwa so:

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

3voto

Steve Jessop Punkte 264569

Um ein Überlaufen zu verhindern:

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

Anstelle von MAX_INT können Sie auch std::numeric_limits<typeof(value)>::max() oder ähnlich, um andere Typen als int zu unterstützen.

2voto

Jim Punkte 1131
  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)

2voto

Omnifarious Punkte 52299

Hier ist eine bessere und kugelsichere Umsetzung als diejenige, die als Antwort akzeptiert wurde, die zudem schnell ist:

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

Sie sollten auch in der Lage sein, daraus eine Inline-Funktion zu machen. Die Überlaufprüfung wird fast immer nach dem ersten Vergleich einen Kurzschluss verursachen. Die Klausel nach der && ist einfach so, dass man (im Falle einer 32-Bit-Zweierkomplement-Ganzzahl) 5 an das Ende von 429496729 anhängen kann, aber nicht 6.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X