簡體   English   中英

在 C 中實現 bigint 的最簡單方法是什么?

[英]What is the simplest way of implementing bigint in C?

我正在嘗試計算 100(即 100 的階乘)。

我正在尋找使用 C 完成此操作的最簡單方法。我已經閱讀過但沒有找到具體答案。

如果你一定要知道,我在 Mac OS X 中編程為 Xcode。

如果您正在尋找一個簡單的庫,libtommath(來自 libtomcrypt)可能就是您想要的。

如果您想自己編寫一個簡單的實現(作為學習練習,或者因為您只需要非常有限的 bigint 功能子集,並且不想依賴於大型庫、命名空間污染等) ,那么我可能會針對您的問題提出以下建議:

由於您可以根據n限制結果的大小,因此只需預先分配所需大小的uint32_t數組來保存結果。 我猜你會想要打印結果,所以使用 10 的冪(即基數 1000000000)而不是 2 的冪的基數是有意義的。也就是說,數組的每個元素都是允許的保持一個介於 0 和 999999999 之間的值。

要將這個數字乘以(正常的,非大的)整數n ,請執行以下操作:

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;

如果您知道n永遠不會大於 100(或其他一些小數)並希望避免進入 64 位范圍(或者如果您在 64 位平台上並希望將uint64_t用於您的 bigint 數組) ,然后將基數設為 10 的較小冪,以便乘法結果始終適合該類型。

現在,打印結果就像:

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

如果您想使用 2 的冪作為底數,而不是 10 的冪,則乘法會變得更快:

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;

但是,以十進制打印結果不會那么令人愉快...... :-) 當然,如果你想要十六進制的結果,那么這很容易:

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

希望這可以幫助! 我將實現其他事情(如加法、2 個 bigint 的乘法等)作為您的練習。 回想一下你在小學是如何學會做基數 10 加法、乘法、除法等的,然后教計算機如何做(但用基數 10^9 或基數 2^32),你應該沒有問題。

如果您願意使用庫實現,標准的似乎是GMP

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

應該算100! 從查看文檔。

你要求最簡單的方法來做到這一點。 所以,給你:

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

我測試了這段代碼,它給出了正確的答案。

您也可以使用OpenSSL bn 它已經安裝在 Mac OS X 中。

只需 30 行代碼、 <stdio.h>char類型,您就可以在 C 中打印階乘 1000:

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

你會發現速度更快,但這里的“小” factorial(10000)是立即計算出來的。

您可以將其放入fact.c文件中,然后編譯 + 執行:

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

如果您想執行一些基本轉換,有一個解決方案,另請參閱Fibonacci(10000) ,謝謝。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM