Was ist der einfachste Weg, bigint in C zu implementieren?

Lesezeit: 5 Minuten

Benutzer-Avatar
AlexBrand

Ich versuche, 100 zu berechnen! (d. h. die Fakultät von 100).

Ich suche nach dem einfachsten Weg, dies mit C zu erreichen. Ich habe herumgelesen, aber keine konkrete Antwort gefunden.

Falls Sie es wissen müssen, ich programmiere in Xcode unter Mac OS X.

  • Los geht’s: 933[100 digits removed]00000 🙂

    – AndersK

    27. Juli 2010 um 3:24 Uhr


  • @Anders: Diese Website ist Stapel Überlauf, nicht Kommentar Überlauf! :-Ö

    – James McNellis

    27. Juli 2010 um 3:25 Uhr


  • lol, ich weiß, dass ich den Wert von Wolframalpha bekommen kann. Ich lerne jedoch C und wollte wissen, wie dies geschehen könnte.

    – AlexBrand

    27. Juli 2010 um 3:33 Uhr

  • Duplikat von “BigInt” in C?

    – aussen

    11. Juli 2011 um 5:32 Uhr


Wenn Sie nach einer einfachen Bibliothek suchen, ist libtommath (von libtomcrypt) wahrscheinlich das, was Sie wollen.

Wenn Sie selbst eine einfache Implementierung schreiben möchten (entweder als Lernübung oder weil Sie nur eine sehr begrenzte Teilmenge der Bigint-Funktionalität benötigen und nicht auf eine Abhängigkeit von einer großen Bibliothek, Namespace-Verschmutzung usw. , dann könnte ich für dein Problem folgendes vorschlagen:

Da können Sie die Größe des Ergebnisses basierend auf einschränken nweisen Sie einfach ein Array von vor uint32_t der erforderlichen Größe, um das Ergebnis zu halten. Ich vermute, du wirst es wollen drucken das Ergebnis, daher ist es sinnvoll, eine Basis zu verwenden, die eine Potenz von 10 ist (dh Basis 1000000000) und nicht eine Potenz von 2. Das heißt, jedes Element Ihres Arrays darf einen Wert zwischen 0 und 999999999 enthalten.

Um diese Zahl mit einer (normalen, nicht großen) ganzen Zahl zu multiplizieren nmach sowas wie:

uint32_t carry=0;
for(i=0; i<len; i++) {
    uint64_t tmp = n*(uint64_t)big[i] + carry;
    big[i] = tmp % 1000000000;
    carry = tmp / 1000000000;
}
if (carry) big[len++] = carry;

Wenn Sie wissen n niemals größer als 100 (oder eine andere kleine Zahl) sein und vermeiden möchten, in den 64-Bit-Bereich zu gehen (oder wenn Sie auf einer 64-Bit-Plattform sind und verwenden möchten uint64_t für Ihr Bigint-Array), dann machen Sie die Basis zu einer kleineren Potenz von 10, damit das Multiplikationsergebnis immer in den Typ passt.

Jetzt ist das Drucken des Ergebnisses nur so etwas wie:

printf("%lu", (long)big[len-1]);
for(i=len-1; i; i--) printf("%.9lu", (long)big[i-1]);
putchar('\n');

Wenn Sie anstelle einer Zehnerpotenz eine Zweierpotenz als Basis verwenden möchten, wird die Multiplikation viel schneller:

uint32_t carry=0;
for(i=0; i<len; i++) {
    uint64_t tmp = n*(uint64_t)big[i] + carry;
    big[i] = tmp;
    carry = tmp >> 32;
}
if (carry) big[len++] = carry;

Das Ergebnis dezimal auszugeben wird jedoch nicht so angenehm sein… 🙂 Natürlich, wenn Sie das Ergebnis in hexadezimaler Form wollen, dann ist es einfach:

printf("%lx", (long)big[len-1]);
for(i=len-1; i; i--) printf("%.8lx", (long)big[i-1]);
putchar('\n');

Hoffe das hilft! Ich überlasse die Implementierung anderer Dinge (wie Addition, Multiplikation von 2 Bigints usw.) als Übung für Sie. Denken Sie einfach daran zurück, wie Sie in der Grundschule Addition, Multiplikation, Division usw. zur Basis 10 gelernt haben, und bringen Sie dem Computer bei, wie das geht (aber stattdessen in Basis 10^9 oder Basis 2^32), und Sie sollten es tun habe kein Problem.

  • Ein Kommentar zu den 64-Bit-Typen auf 32-Bit-Zielen: Auf jeder vernünftigen Hardware erzeugt eine 32×32-Multiplikation von Natur aus ein 64-Bit-Ergebnis, sodass es nicht ineffizient ist, in einen Typ umzuwandeln, der größer als die Wortgröße des Systems ist. Der Compiler generiert die korrekte 32×32->64-Multiplikationsanweisung, falls vorhanden. Und zumindest auf i386 ist die 64/32->32-Division (wenn die oberen 32 Bit kleiner als der Divisor sind) ein inhärentes Merkmal der 32-Bit-Divisionsanweisung und erfordert keine Emulation in der Software durch den Compiler. Auf weniger intelligenten 32-Bit-Zielen möchten Sie jedoch möglicherweise 16-Bit-Einheiten verwenden.

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    27. Juli 2010 um 7:17 Uhr

  • Wenn Sie einen Bibliotheksaufruf durchführen, anstatt die gesamte Operation auf jeder Instanz zu inlinen, was der Compiler meiner Erfahrung nach immer mit integrierten 64-Bit-Operationen auf einer 32-Bit-Plattform durchführt, kann die Codegröße aufgebläht werden. obwohl die Inline-Operation höchstwahrscheinlich schneller sein wird. Dies ist ein Problem, auf das ich oft auf 32-Bit-Embedded-ARM-Plattformen gestoßen bin.

    – Morten Jensen

    30. Juni 2015 um 18:39 Uhr

Wenn Sie bereit sind, eine Bibliotheksimplementierung zu verwenden, scheint die Standardimplementierung zu sein GMP

mpz_t out;
mpz_init(out);
mpz_fac_ui(out,100);
mpz_out_str(stdout,10,out);

sollte 100 rechnen! vom Blick in die Dokumente.

Du hast nach dem gefragt einfachste Weg, dies zu tun. Also, los geht’s:

#include <gmp.h>
#include <stdio.h>

int main(int argc, char** argv) {
    mpz_t mynum;
    mpz_init(mynum);
    mpz_add_ui(mynum, 100);
    int i;
    for (i = 99; i > 1; i--) {
        mpz_mul_si(mynum, mynum, (long)i);
    }
    mpz_out_str(stdout, 10, mynum);
    return 0;
}

Ich habe diesen Code getestet und er gibt die richtige Antwort.

  • Es gibt einen in Scotts Antwort.

    – JeremyP

    27. Juli 2010 um 13:16 Uhr

Benutzer-Avatar
lhf

Sie können auch verwenden OpenSSL Mrd; Es ist bereits in Mac OS X installiert.

Benutzer-Avatar
Michel

Sie können Fakultät 1000 in C mit nur 30 Codezeilen drucken, <stdio.h> und verkohlen Typ :

#include <stdio.h>
#define B_SIZE 3000 // number of buffered digits

struct buffer {
    size_t index;
    char data[B_SIZE];
};

void init_buffer(struct buffer *buffer, int n) {
    for (buffer->index = B_SIZE; n; buffer->data[--buffer->index] = (char) (n % 10), n /= 10);
}

void print_buffer(const struct buffer *buffer) {
    for (size_t i = buffer->index; i < B_SIZE; ++i) putchar('0' + buffer->data[i]);
}

void natural_mul_buffer(struct buffer *buffer, const int n) {
    int a, b = 0;
    for (size_t i = (B_SIZE - 1); i >= buffer->index; --i) {
        a = n * buffer->data[i] + b;
        buffer->data[i] = (char) (a % 10);
        b = a / 10;
    }
    for (; b; buffer->data[--buffer->index] = (char) (b % 10), b /= 10);
}

int main() {
    struct buffer number_1 = {0};
    init_buffer(&number_1, 1);
    for (int i = 2; i <= 100; ++i)
        natural_mul_buffer(&number_1, i);
    print_buffer(&number_1);
}

Schneller findet man aber die „Kleinen“ factorial(10000) wird hier ≈ sofort berechnet.

Sie können es in a setzen fact.c Datei dann kompilieren + ausführen:

gcc -O3 -std=c99 -Wall -pedantic fact.c ; ./a.out ;

Wenn Sie eine Basiskonvertierung durchführen möchten, gibt es eine Lösung, siehe auch Fibonacci(10000), Danke.

  • Es wäre in 40 Codezeilen lesbar …

    – David C. Rankin

    15. April um 2:08 Uhr

  • Es wäre in 40 Codezeilen lesbar …

    – David C. Rankin

    15. April um 2:08 Uhr

1350930cookie-checkWas ist der einfachste Weg, bigint in C zu implementieren?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy