浮点算术模拟
算法原理:浮点数的秘密生活
算法:Floating-Point Arithmetic Simulation(浮点算术模拟)
来源:TAOCP 第2卷 第4.2节
文件:float_arithmetic.c
5W1H
Who(谁研究)
Donald Knuth 在 TAOCP 第4章系统分析了浮点算术的理论基础,这一主题由 John Backus(FORTRAN 设计者)等先驱在1950年代奠定,IEEE 754 标准(1985年)是其最终成果。
What(是什么)
用纯整数模拟规格化浮点数的四则运算(加减乘除),不使用 C 内建的float或double类型进行核心运算。表示方式:
值 = sign × mantissa × 10^exponent 其中 mantissa ∈ [100, 999](规格化,BASE=1000)When(何时使用)
- 教学目的:理解浮点数规格化、指数对齐、舍入误差的本质
- 嵌入式系统:无 FPU 的处理器上模拟浮点
- 精确算术库的设计基础
Where(在哪里重要)
TAOCP 第4.2节用大量篇幅讨论浮点数的精度、规格化、舍入误差分析,是理解为什么0.1 + 0.2 ≠ 0.3(在二进制浮点中)的理论基础。
Why(为什么重要)
理解浮点数的内部机制,对于:
- 数值分析(避免灾难性消去)
- 算法设计(何时需要补偿求和、Kahan算法等)
- 调试精度相关 bug
至关重要。直接用整数实现迫使程序员真正面对每一步规格化过程。
How(如何实现)
数据结构:
typedefstruct{intsign;/* 1=正, -1=负, 0=零 */intmantissa;/* [100, 999] */intexponent;/* 10的指数 */}FloatNum;关键操作:
- 规格化:调整 mantissa 到 [100,999],相应修正 exponent
- 加法:对齐指数(指数小的右移),相加尾数,再规格化
- 乘法:尾数相乘,指数相加,规格化
- 除法:尾数放大后做整数除法,调整指数
需求定义
功能需求
FloatNum结构体:{ int sign; int mantissa; int exponent; }float_add(a, b)— 对齐指数后相加,规格化float_sub(a, b)— 等价于float_add(a, -b)float_mul(a, b)— 尾数乘积,指数求和,规格化float_div(a, b)— 放大后整数除法,规格化float_to_double(a)— 转为 double 用于验证(内部用int_pow10实现,不调用pow)float_normalize(sign, mantissa, exponent)— 内部规格化
非功能需求
- 核心运算不使用
float/double(float_to_double仅用于测试输出) - 不使用
math.h,不链接-lm - BASE=1000,mantissa 三位精度
- 编译无警告:
gcc -std=c99 -Wall
约束
- 不处理 NaN / Inf(超出本教学实现范围)
- 精度:3位有效十进制数字(BASE=1000对应 log₁₀(1000)=3 位精度)
- exponent 范围:int 可表示(约 ±2×10⁹,实际使用远小于此)
验收标准
| 测试 | 输入 | 期望结果 | 容差 |
|---|---|---|---|
| 乘法精度 | 3.14 × 2.00 | ≈ 6.28 | 1% |
| 指数对齐加法 | 1.00 + 0.001 | ≈ 1.001 | 0.5% |
| 除法精确 | 10.0 ÷ 2.0 | = 5.0 | 0.1% |
| 零加法 | 0 + 3.14 | = 3.14 | 0.5% |
| 零减法 | 3.14 - 3.14 | = 0(精确) | — |
| 大数乘法 | 999×10⁵⁰ × 999×10⁵⁰ | 规格化,不崩溃 | — |
| 负数乘法 | (-3.14) × 2.00 | ≈ -6.28 | 1% |
精度说明
BASE=1000 意味着每个数有3位十进制有效数字。这与 IEEE 754 单精度(约7位)相比精度较低,但足以演示规格化原理。若需更高精度,可将 BASE 改为 10⁷ 或更大(注意 mantissa 乘法时需要 long long)。
生成日期:2026-03-22
系列:The Art of Computer Programming 实现集