参阅上一篇:bellard.org : QuickJS 如何使用 qjs 执行 js 脚本
(Fibonacci sequence)斐波那契数列第 n 项的十进制位数 w 与 n 的数学关系可用以下公式近似表示:
推导过程:
示例验证:
当 n=100 , 计算 w := 100*0.2089878 +1 = 21.89878 := 22
:= 读作 约等于。BigInt 符号(+, -) 需要占1位。
校验,运行 python fibonacci.py 100
F(100): 354224848179261915075
结论:
斐波那契数的位数 w 与 n 呈近似线性关系,比例系数为 log10(ϕ),公式误差随 n 增大可忽略。
从 bellard.org 下载 tcc-0.9.27-win64-bin.zip 到 D:\tcc\ , 然后解压。
cd D:\tcc\tcc
为了计算 斐波那契数列(Fibonacci sequence),编写 fib_bigint.c 如下
#include <stdio.h>
#include <stdlib.h> // atoi()
#include <string.h>
#define MAXLEN 13600
// 初始化 bigint a(0), b(1), c(0);
char a[MAXLEN] = {'0'};
char b[MAXLEN] = {'1'};
char c[MAXLEN] = {'0'};
// 将大数存储为字符串形式,并通过反转操作使低位对齐以便计算
void reverseString(char *str) {
int len = strlen(str);
for (int i = 0; i < len / 2; i++) {
char temp = str[i];
str[i] = str[len - i - 1];
str[len - i - 1] = temp;
}
}
// 逐位加法与进位处理
void addBigInt(char *num1, char *num2)
{
int len1 = strlen(num1), len2 = strlen(num2);
int maxLen = (len1 > len2) ? len1 : len2;
int carry = 0;
for (int i = 0; i < maxLen; i++) {
int digit1 = (i < len1) ? (num1[i] - '0') : 0;
int digit2 = (i < len2) ? (num2[i] - '0') : 0;
int sum = digit1 + digit2 + carry;
c[i] = (sum % 10) + '0';
carry = sum / 10;
}
if (carry > 0) c[maxLen++] = carry + '0';
c[maxLen] = '\0';
return;
}
// Fibonacci Series compute
char* calc_fib(int n)
{
if (n <= 0) return "0";
if (n == 1) return "1";
for(int i = 2; i <= n; i++) {
addBigInt(a, b); // 和值存入 c
strcpy(a, b);
strcpy(b, c);
}
return b;
}
int main(int argc, char **argv)
{
int n;
if (argc < 2) {
printf("usage: fib_bigint n \n"
"Compute nth Fibonacci number\n");
return 1;
}
n = atoi(argv[1]);
if (n <=0){ printf("input error"); return 1;}
// MAXLEN: 13600/0.2089878 := 65075.57 -2 := 65074
if (n >= 65074){ printf("input too big: n < 65074",n); return 2;}
char* res = calc_fib(n);
if(strlen(res) >1) printf("%d: ", strlen(res));
reverseString(res);
printf("fib(%d) = %s\n", n, res);
return 0;
}
关键注意事项
- 对齐问题:反转字符串确保低位对齐,简化计算逻辑。
- 进位处理:每一步相加需更新进位,循环结束后检查剩余进位。
- 动态内存:结果数组需动态分配以避免栈溢出,并及时释放。
- 前导零处理:反转结果前需跳过可能的无效前导零(如输入“0098”)。
编译 tcc fib_bigint.c -o fib_bigint.exe
运行 fib_bigint 1000
209: fib(1000) = 43466557686937456435688527675040625802564660517371780402481729089536555417949051890403879840079255169295922593080322634775209689623239873322471161642996440906533187938298969649928516003704476137795166849228875
运行 fib_bigint 66000
input too big: n < 65074
也可以即时运行 tcc -run fib_bigint.c 10000
2090: fib(10000) = ......
cd D:\tcc\quickjs-cosmo-2025-04-26
校验:qjs fib_bigint.js 1000
43466557686937456435688527675040625802564660517371780402481729089536555417949051890403879840079255169295922593080322634775209689623239873322471161642996440906533187938298969649928516003704476137795166849228875