在 8 位微控制器上,我想执行以下操作:
16bit_integer = another_16bit_integer * 0.997;
尽可能少的指令。
32位整数算术怎么样?
16bit_integer = (int16_t) (another_16bit_integer * (int32_t) 997 / 1000);
32 位足以存储 (INT16_MAX × 997),对大 1000 倍的值求和,然后再除回到 16 位刻度。
位移通常非常快:
y = 0xFF3B * (int32_t) x >> 16;
这可能最好写成:
y = (0.997 * 0x10000) * (int32_t)x >> 16;
一个好的编译器会产生等效的输出。
如果您的整数是有符号的,则常量应更改为 0x8000 和 15。
您可能打算在那里进行一些舍入,而不是将结果截断为整数,否则操作的目的实际上是有限的。
但是,由于您使用该特定公式提出了问题,因此您想起了您的结果集确实很粗糙。对于前 333 个数字,结果为:another_16bit_integer-1。你可以用类似的东西来近似它(甚至可能是完全正确的,当我没有在脑海中执行时):
16bit_integer = another_16bit_integer - 1 - (another_16bit_integer/334);
编辑:无符号整数,你自己处理 0 。
在我的平台上(Atmel AVR 8 位微控制器,运行 gcc)
16bit_integer = another_16bit_integer * 0.997;
大约需要 26 条指令。
16bit_integer = (int16_t) (another_16bit_integer * (int32_t) 997 / 1000);
大约需要 25 条指令。
这是执行此操作的一种非常快速的方法:
a = b * 0.99609375;
它与您想要的相似,但速度要快得多。
a = b;
a -= b>>8;
或者使用仅适用于小端系统(如 PIC)的技巧甚至更快。
a = b;
a -= *((int8*)((&b)+1));
在我的脑海中,这归结为 PIC18 上的以下汇编程序:
; a = b
MOVFF 0xc4, 0xc2
NOP
MOVFF 0xc5, 0xc3
NOP
; a -= *((int8*)((&b)+1));
MOVF 0xc5, w
SUBWF 0xc2, f
BTFSC STATUS, C
DECF 0xc
预计算查找表:
16bit_integer = products[another_16bit_integer];
预计算查找表:
16bit_integer = products[another_16bit_integer];
这在 AVR 上不会那么好用,16 位地址空间将被耗尽。
由于您使用的是 8 位处理器,因此您可能只能处理 16 位结果,而不是 32 位结果。为了减少 16 位溢出问题,我将重述如下公式:
result16 = operand16 - (operand16 * 3)/1000
这将为高达 21845 的无符号整数或高达 10922 的有符号整数提供准确的结果。我假设处理器可以进行 16 位整数除法。如果你不能,那么你需要以艰难的方式进行除法。如果不存在乘法指令或乘法仅适用于 8 位操作数,则乘以 3 可以通过简单的移位和加法来完成。
如果不知道确切的微处理器,就不可能确定这样的计算需要多长时间。
在我的平台上(Atmel AVR 8 位微控制器,运行 gcc)
16bit_integer = another_16bit_integer * 0.997;
大约需要 26 条指令。
16bit_integer = (int16_t) (another_16bit_integer * (int32_t) 997 / 1000);
大约需要 25 条指令。
Atmel AVR是 RISC 芯片,因此计数指令是有效的比较。