ISP图像处理中大数乘法溢出处理(二)

目录

1、数学原理拆解

[2、映射到你 ISP 直方图场景](#2、映射到你 ISP 直方图场景)

✅最关键溢出安全点

3、分步数值实例演算

使用拆分公式分步算

[4、纯 32‑bit 无 64 位依赖 C 标准实现](#4、纯 32‑bit 无 64 位依赖 C 标准实现)

[5、边界极限测试(total 取最大 32bit 值)](#5、边界极限测试(total 取最大 32bit 值))

[6、算法适用边界 & 注意事项(ISP 工程坑点)](#6、算法适用边界 & 注意事项(ISP 工程坑点))

[7、扩展:适合 Verilog/RTL 硬件实现思路](#7、扩展:适合 Verilog/RTL 硬件实现思路)


公式完整推导:

1、数学原理拆解

任意整数 A 都可以写成带余除法形式:

其中:

  • → 商(整数除法结果)
  • → 余数,约束条件:

两边同乘 B:

两边除以 C

向下取整(C 语言无符号整数 / 就是向下截断取整):


2、映射到你 ISP 直方图场景

算式:

对应参数:

  • :直方图总像素,uint32_t,最大 4294967295
  • :百分比系数,如 95,范围一般 0~100
  • ,固定除数

代入公式

✅最关键溢出安全点

余数定义:所以 r 的取值范围只能是:0 ~ 99

第二部分乘法:r * ratio ratio 最大 = 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

直接计算真值:

使用拆分公式分步算

  1. ✅结果完全相等,无误差。

再来一个带截断的例子(不能整除): 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 工程坑点)

  1. 此拆分公式仅保证向下取整结果等价 ,和 C 语言 (A*B)/C 截断行为 100% 一致;

  2. 该安全特性成立前提:r*B < 2^32; 在场景 C=100 → r<100;只要 B ≤ 42 949 672,r*B 就永远不会溢出; ratio ≤ 100 完全满足条件;

  3. 如果你的 ratio 可以大于 4200 万,这个算法就不再安全;但百分比阈值场景 ratio 不会超过 100;

  4. 对比错误写法(很多人偷懒):

    复制代码
    // ❌错误!精度大量丢失!!
    thresh = (total / 100U) * ratio;

    它丢掉了余数 r 带来的贡献(也就是上面代码里的 part2),会产生明显误差,高分辨率大像素直方图下误差肉眼可见; 而我们的 SafeMulDiv32 补上了 part2,精度无损。


7、扩展:适合 Verilog/RTL 硬件实现思路

如果你要给 ISP 硬件直方图模块写硬件逻辑,无除法器可分时序实现:

  1. 第一步:total 除以 100 得到商 q,余数 r
  2. 第二步:q × ratio → part1
  3. 第三步:r × ratio → temp
  4. 第四步:temp 除以 100 → part2
  5. 第五步:part1+part2 输出阈值

流水线可拆成 5 级,全程通路位宽 32bit,不需要 64 位乘法器。

相关推荐
roman_日积跬步-终至千里1 小时前
【算法3】二叉树中的最大路径和
算法
XUEYUAN52121 小时前
IP 池调度算法实战:代理池负载均衡、健康检查与失效剔除机制(2026)
tcp/ip·算法·负载均衡
无小道2 小时前
算法——问题转化
算法
evans在进步2 小时前
LeetCode 53 最大子数组和:一次遍历掌握 Kadane 算法
算法·leetcode·职场和发展
小七在进步2 小时前
数据结构:选择排序
数据结构·算法·排序算法
Nil2082 小时前
leetcode 230二叉搜索树中第k小的元素
算法·leetcode·职场和发展
被怪兽吃掉了2 小时前
5.2.1一维组数定义方式
开发语言·c++·算法
不会就选b2 小时前
Linux之线程进阶---封装信号量
数据结构·算法
不会就选b2 小时前
算法日常・每日刷题--<BFS&&最短路径>4
算法·宽度优先