因为double仅约17位有效数字,无法满足金融、科学模拟等百位精度需求;自定义指针结构体可精确控制内存与精度,适用于无第三方依赖或教学场景。

为什么不用 double 而要自己用指针实现多精度浮点?
因为 double 最多约 17 位有效数字,遇到金融计算、科学模拟或密码学中需要百位以上精度的场景,它直接溢出或舍入失真。自定义结构体 + 动态内存(即用指针管理数位数组)是可控精度的常见做法——但注意:这不是为了替代 MPFR 或 Boost.Multiprecision,而是当你必须从零控制内存布局、避免第三方依赖,或教学理解底层机制时才选这条路。
struct mpf_t 里指针该存什么?怎么分配?
典型设计是把数值拆成符号、指数、动态长度的整数位数组(如 BCD 或十进制 digit 数组),例如:
struct mpf_t {
int sign; // 1 or -1
int exp; // base-10 exponent, e.g. 3.14e5 → exp = 5
int* digits; // heap-allocated array of decimal digits, MSB first
size_t len; // number of valid digits (not including leading zeros)
};
关键实操点:
- 用
new int[n]分配digits,别用malloc——C++ 中混合new/free极易崩溃 -
len必须严格维护:digits[0]是最高位,末尾不补零;运算中需频繁resize,每次 realloc 都得new+copy+delete[] - 指数
exp建议统一为“小数点左移位数”,即123.45存为digits = {1,2,3,4,5},exp = -2(小数点在倒数第 2 位前),这样加减法对齐更直观
加法/减法中指针操作最容易崩在哪?
不是算法逻辑错,而是指针越界和内存重叠。比如两个 mpf_t 相加,结果位数可能比两者都长(如 999 + 1),若预分配空间不足,digits[i] 写入就会踩内存。
必须检查的边界:
- 对齐时先根据
exp差值决定是否在短数末尾补零——但补的是逻辑零,不能真往digits数组里写,否则len失控 - 进位传播必须从最低位(
digits[len-1])开始,用size_t i = a.len > b.len ? a.len : b.len;算出最大索引,再倒序遍历;若用int i且len == 0,会变成大负数下标 - 结果数组长度最多为
max(a.len, b.len) + 1,分配时漏掉+1是高频崩溃点
为什么乘法不用递归指针,而要用临时缓冲区?
因为每位相乘会产生跨位进位,若边算边改原 digits 数组,后续位的计算会污染前面已算结果。正确做法是申请一个足够大的临时 int* 缓冲区(长度 = a.len + b.len),把所有 a.digits[i] * b.digits[j] 累加到 tmp[i+j],最后再统一处理进位并截断前导零。
性能提醒:
- 别在循环里反复
new/delete临时缓冲区——封装成成员函数时,可缓存一个static std::vector<int></int>复用内存 - 十进制实现乘法 O(n²),n 超过 1000 位时明显卡顿;若真要高性能,得切到二进制 + FFT,但那就完全脱离“指针管理位数组”的初衷了
- 除法最复杂:必须手写长除法逻辑,且中间余数要用同样结构体表示,极易因
exp调整错误导致小数点漂移
真正难的不是指针本身,而是每一步运算后都得同步更新 sign、exp、len 三个元数据,且任意一个错,后续所有 digits 解释就全乱。调试时打印整个结构体比单步跟指针更有效。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











