目录
1、数学原理拆解
2、映射到你 ISP 直方图场景
✅最关键溢出安全点
3、分步数值实例演算
使用拆分公式分步算
4、纯 32‑bit 无 64 位依赖 C 标准实现
5、边界极限测试(total 取最大 32bit 值)
6、算法适用边界 & 注意事项(ISP 工程坑点)
7、扩展:适合 Verilog/RTL 硬件实现思路
公式完整推导:![]()
1、数学原理拆解
任意整数 A 都可以写成带余除法形式:
其中:
→ 商(整数除法结果)
→ 余数,约束条件:
两边同乘 B:
两边除以 C
向下取整(C 语言无符号整数/就是向下截断取整):
2、映射到你 ISP 直方图场景
算式:
对应参数:
:直方图总像素,
uint32_t,最大 4294967295:百分比系数,如 95,范围一般 0~100
,固定除数
代入公式
✅最关键溢出安全点
余数定义:所以 r 的取值范围只能是:
0 ~ 99
第二部分乘法:r * ratioratio 最大 = 100:
9900 远远小于 32 位无符号数上限 (42 亿),第二部分乘法永远不会溢出 32bit!
第一部分:,ratio≤100 →
该数值 ≤ 0xFFFFFFFF (4294967295) 👉第一部分乘法在32bit ratio范围为[0,100]场景下也不会溢出 32 位!
这就是为什么这个拆分算法,不用任何 64‑bit (long long /uint64_t),纯 32 位运算就可以安全算出
total*ratio/100
3、分步数值实例演算
举一个实际 ISP 例子:
- total = 2 100 520
- ratio = 95
- C=100
直接计算真值:
使用拆分公式分步算
✅结果完全相等,无误差。
再来一个带截断的例子(不能整除): total= 1000005,ratio=95 真值:(1000005 * 95)/100 = 95000475 / 100 = 950004(向下取整)
拆分计算:
q = 1000005 / 100 = 10000
r = 1000005 % 100 = 5
part1 = 1000095 = 950000
part2 = (595)/100 = 475/100 = 4
result=950000+4=950004 ✅结果完全一致。
4、纯 32‑bit 无 64 位依赖 C 标准实现
#include <stdint.h> /** * @brief 32位安全计算 (A*B)/C 向下取整,无64bit,防止A*B乘法溢出 * @param A 直方图总像素 total * @param B 百分比 ratio (0~100) * @param C 固定除数=100 * @retval (A*B)/C 的结果,uint32 */ static uint32_t SafeMulDiv32(uint32_t A, uint32_t B, uint32_t C) { uint32_t q = A / C; uint32_t r = A % C; uint32_t part1 = q * B; uint32_t part2 = (r * B) / C; return part1 + part2; } /* ===== ISP直方图百分比阈值调用示例 ===== */ uint32_t total = GetHistogramTotalSum(); uint32_t ratio = 95U; uint32_t cumu_th; cumu_th = SafeMulDiv32(total, ratio, 100U);5、边界极限测试(total 取最大 32bit 值)
total = 0xFFFFFFFF (4294967295), ratio=100 真值:(4294967295 * 100)/100 = 4294967295
拆分运算:
q = 4294967295 / 100 = 42949672
r = 4294967295 % 100 = 95
part1 = 42949672 * 100 = 4294967200
part2 = (95*100)/100 = 95
result = 4294967200 + 95 = 4294967295 ✅结果正确,没有溢出。
6、算法适用边界 & 注意事项(ISP 工程坑点)
- 此拆分公式仅保证向下取整结果等价,和 C 语言
(A*B)/C截断行为 100% 一致; - 该安全特性成立前提:
r*B < 2^32; 在场景 C=100 → r<100;只要 B ≤ 42 949 672,r*B 就永远不会溢出; ratio ≤ 100 完全满足条件; - 如果你的 ratio 可以大于 4200 万,这个算法就不再安全;但百分比阈值场景 ratio 不会超过 100;
- 对比错误写法(很多人偷懒):
它丢掉了余数 r 带来的贡献(也就是上面代码里的 part2),会产生明显误差,高分辨率大像素直方图下误差肉眼可见; 而我们的 SafeMulDiv32 补上了 part2,精度无损。// ❌错误!精度大量丢失!! thresh = (total / 100U) * ratio;
7、扩展:适合 Verilog/RTL 硬件实现思路
如果你要给 ISP 硬件直方图模块写硬件逻辑,无除法器可分时序实现:
- 第一步:
total除以 100 得到商 q,余数 r - 第二步:q × ratio → part1
- 第三步:r × ratio → temp
- 第四步:temp 除以 100 → part2
- 第五步:part1+part2 输出阈值
流水线可拆成 5 级,全程通路位宽 32bit,不需要 64 位乘法器。