【问题标题】:How do I compute the 8-bit average of two 8-bit values in assembly?如何计算汇编中两个 8 位值的 8 位平均值?
【发布时间】:2017-04-15 02:45:13
【问题描述】:

使用 Arduino,我必须在 Atmel AVR Assembly 中为我的计算机科学课编写一个函数,计算汇编中两个 8 位值的 8 位平均值。我也不允许使用任何分支指令(但可以跳过)。

这是我目前所拥有的:

.global average
average:
  add r24, r22
  asr r24
  ret

对于我必须计算 69 和 60 的平均值的程序部分,它返回 -64 而不是 64。有人知道我将如何使这个函数工作吗?任何帮助将不胜感激。

【问题讨论】:

  • 求平均值同时避免整数溢出/环绕的技巧:stackoverflow.com/a/3816471/224132。我通过搜索integer average without overflow 在不到一分钟的时间内找到了它,因为我知道那里有 一个技巧,但不记得了。它可能适用于有符号 2 的补码和无符号的,但我没有检查。如果您愿意,可以将signed 放入谷歌搜索词中。
  • 请注意,如果您知道它们的顺序,我链接的答案仅适用于未签名的答案。最高投票的答案不需要,但比 ADD 和 ROR 需要更多的操作。无论如何,这只是表明在寻找整数技巧时,不要将自己局限于 AVR asm。您会在 C 中找到很多东西,您可以自己在 AVR 中实现它们,甚至可以将其提供给编译器,看看它是如何实现的。例如其中一些很有用:graphics.stanford.edu/~seander/bithacks.html

标签: assembly arduino average avr signed


【解决方案1】:

诀窍是将 9 位结果除以 2,然后将 rotate-with-carry 相加,然后将 8 位结果留在寄存器中。

关于我在 cmets 中链接的问题的两个答案使用的是:firstsecond

AVR 的实现是:

    add   r24, r25       ; 9-bit result in C and r24
    ror   r24            ; rotate-through-carry, like x86's RCR instruction

这适用于位的有符号或无符号解释,因为我们所做的只是从加法的 9 位完整结果中丢弃低位。没有算术与逻辑移位的选择,也没有环绕。

还要注意,通过向 -infinity 移动四舍五入来进行除法(不像 C 的整数除法运算符那样截断为零)。所以(1 + -2) >> 1-1


这足够小,您应该将它放在宏中,而不是函数中。在大多数调用站点可能至少需要 2 条指令,因此即使您可以使用 1 字 RCALL instruction 而不是 2 字 CALL,内联它也可以节省代码大小。

【讨论】:

  • 有趣。所以在 x86 中我们可以使用RCL 来达到同样的效果。不幸的是,编译器无法识别这种优化
  • @LưuVĩnhPhúc:是的,除了转换为更大的无符号类型然后使用>> 之外,我不知道如何在 C 中表达这一点。对于比寄存器宽的类型,可能没有编译器会将其优化回 RCL。
  • 在 Intel 上即使 RCL 加 1 也超过 1 uop(Skylake 上为 3),因此对于更窄的参数,64 位或 32 位寄存器中的 ADD + SHR 在 Intel CPU 上更便宜。如果只有一个输入需要额外的指令来进行零扩展,则 MOVZX(或 MOV)/ADD/SHR 通常应该优于 ADD+RCL。特别是因为零扩展 MOV 可以让您以非破坏性方式进行操作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-03-11
  • 1970-01-01
  • 1970-01-01
  • 2013-11-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多