【问题标题】:Faster way to convert a number from range to another range将数字从范围转换为另一个范围的更快方法
【发布时间】:2017-01-03 20:56:33
【问题描述】:

根据this SO question,可以通过计算将一个数字范围转换为另一个(线性转换):

NewValue = (((OldValue - OldMin) * NewRange) / OldRange) + NewMin

但是,我想知道是否还有其他更快的方法可以做到这一点。

考虑一个没有除法指令的微控制器,将大量范围转换为另一个范围(即,将图像文件中的 24 位颜色/像素转换为 LCD 显示器的 18 位颜色/像素)需要一些时间。我在想有什么办法可以优化这个。

【问题讨论】:

  • 这里整数除法的唯一替代方法是浮点乘法。无论你转向哪种方式,你都无法改变基础数学的规则。
  • 我可以想象浮点运算在这些设备上会更慢。
  • 您给定的将范围 (0,2^24-1) 转换为 (0,2^18-1) 的示例可以通过位移来完成(如果您想四舍五入,还可以加一个到最近)
  • @KongChunHo NewValue = OldValue >> 6 将删除 6 个最低有效位。确保您的值是unsigned
  • @SamVarshavchik:永远不要说“唯一”。在这种特殊情况下,一个简单的转变很可能就可以了。在其他情况下,定点会更好。

标签: c++ c performance math optimization


【解决方案1】:

24 位颜色通常为 8 x 3(3 个分量,每个 8 位)。

18 位颜色为 6 x 3。

一个简单的>>2 将8 位值的范围转换为6 位值,“向下舍入”。在大多数硬件上,移位操作都很快。

四舍五入更难,主要是因为溢出。从这个开始:

(x+2)>>2

16 位值。结果是一个从 0 到 2^6 的值,而不是你想要的 0 到 2^6-1。您必须检测最后一种情况。

如果你买得起 ROM,可以使用查找表。 256 个条目并不是那么多。如果您想应用 gamma 或其他校正,这可能更值得考虑。

但实际上,只需 >>2 和/或屏蔽每个组件,然后移动并屏蔽到位。

int32 r = ((pix>>2)&(0x3F<<0))|((pix>>4)&(0x3F<<6))|((pix>>6)&(0x3F<<12));

pix 是一个 32 位值,用于存储 24 位像素,而 r 存储 18 位结果。

这种优化需要在尽可能接近真实环境的情况下进行分析。

【讨论】:

  • 四舍五入在这里不是一个好主意。简单地丢弃低两位会导致统一的变换,其中 4 个源值恰好映射到 1 个目标值,在整个范围内,包括末端。
  • 为什么你只是扯掉每 2 个 MSB(即&amp;0x3F)?这不会使比例不同吗?
  • @KongChunHo 哎呀,每个字节占用 6 个 LSB,而不是 6 个 MSB。修复。
猜你喜欢
  • 1970-01-01
  • 2011-05-12
  • 1970-01-01
  • 2011-10-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-03
相关资源
最近更新 更多