当前位置: 首页 > news >正文

【学Rust写CAD】31 muldiv255函数(muldiv255.rs)

源码

// Calculates floor(a*b/255 + 0.5)
#[inline]
pub fn muldiv255(a: u32, b: u32) -> u32 {
    // The deriviation for this formula can be
    // found in "Three Wrongs Make a Right" by Jim Blinn.
    let tmp = a * b + 128;
    (tmp + (tmp >> 8)) >> 8
}

代码分析

这个 muldiv255 函数是一个高效的实现,用于计算 floor(a * b / 255 + 0.5),也就是将两个无符号整数 a 和 b 相乘,然后除以 255,并进行四舍五入。这种计算在图像处理中很常见,比如在 alpha 混合(alpha blending)或颜色空间转换时。

步骤分解:
  1. a * b + 128:
  • 首先计算 a * b,然后加上 128。这个 128 的作用是为了后续的四舍五入(因为 255 / 2 = 127.5,所以加 128 可以确保正确的舍入)。
  1. tmp + (tmp >> 8):
  • tmp >> 8 相当于 tmp / 256(右移 8 位相当于除以 2^8)。

  • 然后 tmp + (tmp >> 8) 相当于 tmp + tmp / 256。

  1. 8:

  • 最后右移 8 位,相当于除以 256。

为什么这个公式有效?

这个方法的数学原理来自 Jim Blinn 的文章 “Three Wrongs Make a Right”,它利用了近似计算来避免昂贵的除法运算(因为整数除法在 CPU 上通常比乘法和移位慢)。

  • 原本的计算是 (a * b + 127) / 255(四舍五入)。

  • 但 (a * b + 128) * 257 / 65536(即 (tmp + (tmp >> 8)) >> 8)是一个近似计算,可以高效地用移位和加法实现。

数学推导:

  1. 我们希望计算 (a * b + 127) / 255(四舍五入)。

  2. 可以近似为 (a * b + 128) * (256 + 1) / 65536(因为 255 ≈ 65536 / 257)。

展开后:

(a * b + 128) * (256 + 1) / 65536
= (256*(a*b + 128) + (a*b + 128)) / 65536
= ( (a*b + 128) << 8 + (a*b + 128) ) >> 16
= (tmp << 8 + tmp) >> 16
= (tmp + (tmp >> 8)) >> 8

最终得到 (tmp + (tmp >> 8)) >> 8。

示例

假设 a = 100, b = 200:

  1. tmp = 100 * 200 + 128 = 20000 + 128 = 20128

  2. tmp >> 8 = 20128 / 256 = 78

  3. tmp + (tmp >> 8) = 20128 + 78 = 20206

20206 >> 8 = 20206 / 256 = 78(实际 100 * 200 / 255 ≈ 78.431,四舍五入得 78)

为什么不用 (a * b + 127) / 255?

虽然 (a * b + 127) / 255 也能得到正确结果,但:

  • 除法 (/ 255) 在 CPU 上通常比移位和加法慢。

  • 这个优化方法避免了除法,改用移位和加法,性能更高。

适用场景

  • 图像处理(如 alpha 混合、颜色计算)。

  • 需要高效计算 (a * b) / 255 并四舍五入的情况。

总结

这个函数巧妙地利用移位和加法来近似计算 (a * b) / 255 并四舍五入,避免了昂贵的除法运算,是一种高效的位操作优化方法。

http://www.dtcms.com/a/113760.html

相关文章:

  • 设计模式简述(三)工厂模式
  • 《C语言代码解析与应用:数组操作的两种实现》
  • ctfshow VIP题目限免 版本控制泄露源码2
  • LeetCode详解之如何一步步优化到最佳解法:20. 有效的括号
  • 配置ASP.NET Core+NLog配置日志示例
  • 基于 FPGA 的分秒计数器
  • 如何实现两个视频融合EasyCVR平台的数据同步?详细步骤指南
  • 爬虫练习案例
  • zk基础—5.Curator的使用与剖析二
  • 打造高效英文单词记忆系统:基于Python的实现与分析
  • $R^n$超平面约束下的向量列
  • 游戏引擎学习第206天
  • React框架的Hooks实现原理
  • MicroPython 开发ESP32应用教程 之 WIFI简单应用 :时间同步、天气信息获取,ST7735 TFT屏驱动及任意中文字符显示
  • Linux制作deb安装包
  • 卡尔曼滤波器浅聊
  • windows 常用命令总结
  • MySQL表的增删改查基础版
  • 【大模型深度学习】如何估算大模型需要的显存
  • JavaScript基础--09-流程控制语句:选择结构(if和switch)
  • 文件系统-inode/软硬件连接(未完结)
  • 用 Python 制作仓库自动化指南
  • Kotlin协程机制
  • 解析keras.layers.Layer中的权重参数
  • Linux内核——段描述符详解
  • SeaTunnel系列之:Apache SeaTunnel编译和安装
  • 《SQL赋能人工智能:解锁特征工程的隐秘力量》
  • python基础-11-调试程序
  • DrissionPage高级技巧:从爬虫到自动化测试
  • Python FastApi(13):APIRouter