ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

乘数比较大时溢出处理(一)

乘数比较大时溢出处理(一) 目录一、问题二、方案选型按 ISP 嵌入式工程推荐优先级排序方案 164 位中间变量中转方案 2无 64‑bit 硬件极老旧 MCU无uint64_t/long long—— 带余数补偿拆分算法方案 3溢出预判 分支分流不推荐主路径适合异常保护方案 4定点 Q 格式缩放适合无除法硬件、硬件加速 ISP 算子各方案对比表ISP 直方图场景额外工程建议一、问题isp 图像处理中需要统计0-255所有bin d的直方图信息之和。一般ISP会设置不同区域的权重再统计每一个像素进行构建直方图。如果分辨率比较大的时候对其做加权处理后直方图所有bin之和会是一个比较大的数值all_total现在我想对取所有像素的百分比的时候比如 all_total*ratio/100, 设定其其像素进行统计百分比阈值当大于某一阈值进行一些逻辑操作。在32bit系统中当all_total比较大的时候all_total*ratio对 unsigned long 范围可能溢出需要做溢出处理。// 危险代码极易溢出 unsigned long total; uint16_t ratio; unsigned long thresh (total * ratio) / 100U;total是直方图像素总和32‑bitunsigned long最大值0xFFFFFFFF 4294967295 先执行乘法total * ratio乘法结果超出 32 位范围就发生无符号溢出回绕数值错乱之后再除以 100 得到完全错误阈值。溢出临界点例ratio100安全上限 42,949,672只要直方图总像素该值乘法直接溢出。二、方案选型按 ISP 嵌入式工程推荐优先级排序方案 164 位中间变量中转【首选如果系统为64bit优选】核心技巧先把其中一个操作数强制提升到 64bit 再相乘乘法全程在 64 位空间运算永远不会溢出 32bit 像素总和场景。⚠️致命坑不能(uint64_t)(total*ratio)此时乘法已经 32 位溢出后再强转为时已晚#include stdint.h uint32_t CalcPercentThresh(uint32_t total, uint16_t ratio) { /* (uint64_t)total 先提升位宽ratio自动提升为64bit相乘 */ uint64_t temp (uint64_t)total * ratio; temp temp / 100U; /* 结果一定 total安全转回32bit */ return (uint32_t)temp; }适用平台所有带 C99 编译器嵌入式64bit Linux优点零精度损失逻辑最简单无误差无分支判断上限能力total ≤ 4G、ratio ≤ 100乘积最大 400G远小于 64 位上限 (1.8e19)绝对不会溢出。ISP 直方图百分比阈值判断示例累计直方图大于阈值触发逻辑uint32_t total_sum ...; //直方图所有bin总和 uint32_t percent_thresh; percent_thresh (uint32_t)((uint64_t)total_sum * 95U / 100U); //遍历累计直方图找到第一个累计percent_thresh的灰度位置做阈值方案 2无 64‑bit 硬件极老旧 MCU无uint64_t/long long—— 带余数补偿拆分算法直接(total / 100)*ratio会产生截断精度丢失 利用恒等式做精确拆分AtotalBratioC100。uint32_t MulDiv32_NoOverflow(uint32_t A, uint32_t B, uint32_t C) { uint32_t div A / C; uint32_t rem A % C; uint32_t part1 div * B; uint32_t part2 (rem * B)/ C; return part1 part2; } //调用thresh MulDiv32_NoOverflow(total, ratio, 100U);约束rem C本例 C100rem*ratio最大 99*1009900永远不会溢出 32 位完美规避大数乘法溢出。优点纯 32 位运算无 64 位依赖数学结果完全等价 (A*B)/C精度无损缺点多一次除法、取余运算少量耗时适合无 64‑bit 的极简内核。方案 3溢出预判 分支分流不推荐主路径适合异常保护先预判乘法会不会溢出溢出时走备选计算路径。 溢出判定条件/* 判断 total * ratio 是否溢出32bit无符号 */ if (total UINT32_MAX / ratio) { //溢出分支使用拆分除法方案 } else { //安全分支直接运算 thresh (total*ratio)/100U; }缺点代码双分支逻辑复杂ISP 流水线不喜欢条件分支容易引入跳转延迟。方案 4定点 Q 格式缩放适合无除法硬件、硬件加速 ISP 算子如果你不想运行时除法可提前转为定点运算例如 Q8放大 256 倍同样乘法必须 64 位中转防止溢出uint32_t q_factor (ratio * 256U)/100U; uint32_t thresh (uint32_t)(((uint64_t)total * q_factor) 8U);适合硬件 ISP 内核移位代替除法适合做 LCE/AE 实时直方图统计。各方案对比表方案是否需要 64 位精度损失ISP 工程推荐度64bit 中转 (uint64_t)是无损失⭐⭐⭐⭐⭐首选带余数拆分 MulDiv32否无损失⭐⭐⭐⭐ 无 64bit 时使用先除后乘无余数补偿否有截断误差❌禁止使用溢出预判分支是 / 否无损失⭐⭐ 仅做防护Q 定点缩放是微小舍入误差⭐⭐⭐适合硬件算子ISP 直方图场景额外工程建议永远优先用 (uint64_t) 强转方案如果图像信号处理器 ARM 内核都支持 64 位优先使用不要为了省一点点周期牺牲溢出安全性直方图总像素经常可达 200 万、800 万、1200 万像素极易触发 32‑bit 乘法溢出百分比阈值逻辑90%、95% 累计直方图截断DRC / 阴影抑制的工业标准代码范式//累计直方图百分比阈值 uint32_t hist_sum GetHistTotalSum(); uint32_t cumu_th (uint32_t)((uint64_t)hist_sum * 95U / 100U); uint32_t cum_sum 0; uint32_t gray_th 255; for(int bin0;bin255;bin) { cum_sum hist[bin]; if(cum_sum cumu_th) { gray_th bin; break; } } //使用gray_th做后续图像亮度分割逻辑
返回列表