Frage

Ich mag eine große int-Klasse in C ++ als Programmier exercise-Klasse implementieren, die Zahlen größer als ein long int verarbeiten kann. Ich weiß, dass es mehrere Open-Source-Implementierungen sind da draußen schon, aber ich mag meine eigenen schreiben. Ich versuche, ein Gefühl dafür zu bekommen, was der richtige Ansatz ist.

Ich verstehe, dass die allgemeine Strategie ist es, die Zahl als String erhalten, und es dann in kleinere Zahlen (einstelligen Bereich zum Beispiel) brechen, und sie in einem Array platzieren. An diesem Punkt sollte es relativ einfach sein, die verschiedenen Vergleichsoperatoren zu implementieren. Mein Hauptanliegen ist, wie ich Dinge wie Addition und Multiplikation implementieren würde.

Ich suche eine allgemeine Ausrichtung und Beratung für tatsächliche Arbeits Code gegenüber.

War es hilfreich?

Lösung

termin für eine große int-Klasse zu berücksichtigen:

  1. Mathematische Operatoren: +, -, /, *% Vergessen Sie nicht, dass Ihre Klasse auf beiden Seiten der sein kann, Betreiber, dass die Betreiber kann sein gekettet, dass einer der Operanden könnte ein int, float, double, etc.

  2. E / A-Operatoren: >>, << Dies ist wo Sie herausfinden, wie man richtig Erstellen Sie Ihre Klasse von Benutzereingaben, und wie es zu formatieren als auch für die Ausgabe.

  3. Conversions / Casts: Herauszufinden welche Arten / Klassen Ihr großer int Klasse sollte konvertierbar sein, und wie man richtig handhaben die Umwandlung. Eine kurze Liste würde gehören Doppel- und Schwimmer und kann umfassen int (mit der richtigen Grenzen Überprüfung) und komplexen (vorausgesetzt, es verarbeiten kann die Reichweite).

Andere Tipps

Ein Spaß Herausforderung. :)

Ich gehe davon aus, dass Sie ganze Zahlen von beliebiger Länge möge. Ich schlage vor, den folgenden Ansatz:

Betrachten Sie die binäre Natur des Datentyps „int“. Denken Sie über einfache binäre Operationen mit emulieren, was die Schaltungen in Ihrer CPU tun, wenn sie Dinge hinzufügen. Falls Sie daran interessiert, mehr in die Tiefe, betrachten diesem Wikipedia-Artikel über Halbaddierer Lesen und Volladdierer . Sie werden etwas zu tun, ähnlich der sein, aber man kann so niedriges Niveau wie die nach unten gehen - aber faul, ich dachte, ich würde nur eine noch einfachere Lösung verzichten und finden.

Aber, bevor sie in irgendwelchen algorithmischen Details gehen zu addieren, subtrahieren, multiplizieren, lassen Sie uns einige Datenstruktur finden. Ein einfacher Weg ist natürlich, die Dinge in einem std :: vector zu speichern.

template< class BaseType >
class BigInt
{
typedef typename BaseType BT;
protected: std::vector< BaseType > value_;
};

Vielleicht möchten Sie prüfen, ob Sie den Vektor mit einer festen Größe machen wollen und wenn es vorzubelegen. Grund dafür ist, dass für verschiedene Operationen, werden Sie durch jedes Element des Vektors gehen müssen - O (n). Vielleicht möchten Sie ohne Weiteres wissen, wie komplex eine Operation sein wird und eine feste n genau das tut.

Aber jetzt einige Algorithmen auf die Zahlen auf Betrieb. Man könnte es auf einer logischen Ebene tun, aber wir werden diese Magie CPU-Leistung verwenden, um Ergebnisse zu berechnen. Aber was wir von der Logik-Darstellung von Half- übernehmen und FullAdders ist der Weg, es befasst sich mit trägt. Als Beispiel betrachten wir, wie Sie die Umsetzung würde + = Operator . Für jede Zahl in BigInt <> :: Wert_, würden Sie diese und sehen hinzufügen, wenn das Ergebnis eine gewisse Form von Carry erzeugt. Wir werden es nicht bitweise tun, sondern verlassen sich auf die Natur unserer Basetype (sei es lang oder int oder kurz oder was auch immer): es überläuft.

Sicher, wenn Sie zwei Zahlen addieren, muss das Ergebnis größer als die größere eine dieser Zahlen, nicht wahr? Wenn es nicht ist, dann überschwemmte das Ergebnis.

template< class BaseType >
BigInt< BaseType >& BigInt< BaseType >::operator += (BigInt< BaseType > const& operand)
{
  BT count, carry = 0;
  for (count = 0; count < std::max(value_.size(), operand.value_.size(); count++)
  {
    BT op0 = count < value_.size() ? value_.at(count) : 0, 
       op1 = count < operand.value_.size() ? operand.value_.at(count) : 0;
    BT digits_result = op0 + op1 + carry;
    if (digits_result-carry < std::max(op0, op1)
    {
      BT carry_old = carry;
      carry = digits_result;
      digits_result = (op0 + op1 + carry) >> sizeof(BT)*8; // NOTE [1]
    }
    else carry = 0;
  }

  return *this;
}
// NOTE 1: I did not test this code. And I am not sure if this will work; if it does
//         not, then you must restrict BaseType to be the second biggest type 
//         available, i.e. a 32-bit int when you have a 64-bit long. Then use
//         a temporary or a cast to the mightier type and retrieve the upper bits. 
//         Or you do it bitwise. ;-)

Die andere arithmetische Operation geht analog. Heck, Sie könnte sogar den stl-functors std :: plus und std :: minus, std :: Zeiten und std :: dividieren, ..., aber das Übertrag kümmern. :) Sie können auch Multiplikation und Division implementieren, indem Sie Ihre Plus- und Minus-Operatoren, aber das ist sehr langsam, weil die Ergebnisse neu berechnet würden Sie bereits in früheren Anrufen auf plus berechnet und Minus in jeder Iteration. Es gibt viele gute Algorithmen gibt für diese einfache Aufgabe, verwenden wikipedia oder das Web

Und natürlich sollten Sie Standard-Operatoren wie operator<< implementieren (nur jeden Wert verschieben in Wert_ nach links für n Bits, am value_.size()-1 gestartet ... ach ja, und erinnere mich an die Übertrags :), operator< - Sie können sogar optimieren ein wenig hier zunächst die grobe Anzahl der Stellen mit size() überprüfen. Und so weiter. Dann ist Ihre Klasse nützlich machen, indem befriendig std :: ostream operator<<.

Hope dieser Ansatz ist hilfreich!

Es gibt einen kompletten Abschnitt dazu: [The Art of Computer Programming, Band 2:. Seminumerical Algorithmen, Abschnitt 4.3 Multiple Precision Arithmetic, S. 265-318 (ed.3)]. Sie können andere interessante Materialien finden Sie in Kapitel 4, Arithmetik.

Wenn Sie wirklich wollen nicht zu einer anderen Implementierung suchen, haben Sie darüber nachgedacht, was es Sie sind aus zu lernen? Es gibt unzählige Fehler gemacht werden, und diejenigen, die Aufdeckung ist lehrreich und auch gefährlich. Darüber hinaus gibt es Herausforderungen in wichtigen Rechen Volkswirtschaften zu identifizieren und geeignete Speicherstrukturen für ernsthafte Performance-Probleme zu vermeiden.

Eine Herausforderung Frage für Sie: Wie wollen Sie Ihre Implementierung testen und wie wollen Sie zeigen, dass es Arithmetik richtig?

Sie könnten eine weitere Implementierung wollen gegen testen (ohne zu sehen, wie sie es tut), aber es wird länger dauern als das, ohne zu erwarten eine excrutiating Teststufe verallgemeinern zu können. Vergessen Sie nicht, Ausfallmodi (aus Gedächtnisproblemen, aus Stapel, läuft zu lange, usw.).

zu betrachten

Viel Spaß!

Außerdem würde wahrscheinlich in der Standard-linearen Zeit Algorithmus durchgeführt werden müssen,
aber für die Multiplikation könnten Sie versuchen, http://en.wikipedia.org/wiki/Karatsuba_algorithm

Wenn Sie die Ziffern der Zahl in einem Array haben, können Sie tun, Addition und Multiplikation genau so, wie Sie sie Langschrift tun würde.

Vergessen Sie nicht, dass Sie sich nicht als Ziffern 0-9 beschränken müssen, das heißt Verwendung Bytes als Ziffern (0-255), und Sie können das gleiche wie für Dezimalstellen lange Hand Arithmetik noch tun. Man könnte sogar eine Reihe von lang verwenden.

Ich bin nicht eine Zeichenfolge verwendet, ist der richtige Weg zu gehen überzeugt - obwohl ich nie Code selbst geschrieben, denke ich, dass eine Reihe von einer Basis numerischen Typ unter Verwendung könnte eine bessere Lösung sein. Die Idee ist, dass Sie würde einfach erweitern, was Sie bereits haben die gleiche Art und Weise bekam die CPU ein einzelnes Bit in eine ganze Zahl erstreckt.

Wenn Sie beispielsweise eine Struktur haben,

typedef struct {
    int high, low;
} BiggerInt;

Sie können dann manuell ausführen nativen Operationen auf der Grundlage der „Ziffern“ (hoch und niedrig, in diesem Fall), achtsam von Überlaufbedingungen:

BiggerInt add( const BiggerInt *lhs, const BiggerInt *rhs ) {
    BiggerInt ret;

    /* Ideally, you'd want a better way to check for overflow conditions */
    if ( rhs->high < INT_MAX - lhs->high ) {
        /* With a variable-length (a real) BigInt, you'd allocate some more room here */
    }

    ret.high = lhs->high + rhs->high;

    if ( rhs->low < INT_MAX - lhs->low ) {
        /* No overflow */
        ret.low = lhs->low + rhs->low;
    }
    else {
        /* Overflow */
        ret.high += 1;
        ret.low = lhs->low - ( INT_MAX - rhs->low ); /* Right? */
    }

    return ret;
}

Es ist ein bisschen wie ein einfaches Beispiel, aber es sollte ziemlich offensichtlich sein, wie auf eine Struktur zu erweitern, die eine variable Anzahl von was auch immer Basis numerischer Klasse hatte Sie verwenden.

Wie schon andere gesagt, tut es auf altmodische lange Hand Art und Weise, aber bleiben Sie weg dies zu tun, alle in der Basis 10. Ich würde vorschlagen, dass sie alle in der Basis 65.536 und Speicher Dinge in einer Reihe von Long-Positionen zu tun.

Mit den Algorithmen Sie in der 1. bis 4. Klasse gelernt.
Beginnen Sie mit der diejenigen Spalte, dann die Zehner, und so weiter.

Wenn Sie Ihre Zielarchitektur BCD (binär codierte Dezimalzahl) Darstellung von Zahlen unterstützt, können Sie einige Hardware-Unterstützung für die Langschrift Multiplikation / Addition erhalten, dass Sie tun müssen. Abrufen der Compiler BCD Anweisung auszusenden ist etwas, das Sie gelesen haben, auf bis zu ...

Die Motorola 68K-Serie Chips hatten dies. Nicht, dass ich bitter oder nichts.

Mein Start wäre eine beliebige Größe Array von ganzen Zahlen zu haben, 31 Bit und die 32n'd als Überlauf verwendet wird.

Der Starter op wäre ADD, und dann, MAKE-NEGATIVE, unter Verwendung von 2-Komplement. Danach fließt Subtraktion trivialer, und wenn Sie hinzufügen müssen / sub, alles andere ist machbar.

Es gibt wahrscheinlich anspruchsvollere Ansätze. Dies würde aber der naive Ansatz von digitaler Logik sein.

könnten versuchen, so etwas wie diese Umsetzung:

http://www.docjar.org/html/ api / java / math / BigInteger.java.html

Sie würden nur noch 4 Bits für eine einzelne Ziffer von 0 bis 9

So ein Int Wert erlauben würde, bis zu 8 Stellen je. Ich habe ich beschlossen, mit einer Reihe von Zeichen kleben würde, so dass ich die doppelte Speicher verwenden, aber für mich ist es nur 1 Mal verwendet wird.

Auch wenn alle Ziffern in einer einzigen Speicherung int es sie über kompliziert und wenn alles, was es kann es sogar verlangsamen.

Ich habe keine Speed-Tests, sondern an der Java-Version von BigInteger sucht es scheint, wie es eine Menge Arbeit tut.

Für mich ich die unten

//Number = 100,000.00, Number Digits = 32, Decimal Digits = 2.
BigDecimal *decimal = new BigDecimal("100000.00", 32, 2);
decimal += "1000.99";
cout << decimal->GetValue(0x1 | 0x2) << endl; //Format and show decimals.
//Prints: 101,000.99

subtrahieren 48 von der Zeichenfolge von Integer- und Druck Anzahl großer Ziffer zu erhalten. dann führt die grundlegende mathematische Operation.    sonst werde ich vollständige Lösung.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top