简体   繁体   English

将16位整数与double相乘的最快方法是什么?

[英]What is the fastest way to multiply a 16-bit integer with a double?

On an 8-bit micro controller I would like to do the following: 在8位微控制器上,我想做以下事情:

16bit_integer = another_16bit_integer * 0.997;

with the least possible number of instructions. 尽可能少的指令。

How about integer arithmetic in 32 bits? 32位整数运算怎么样?

16bit_integer = (int16_t) (another_16bit_integer * (int32_t) 997 / 1000);

32 bits will be enough to store (INT16_MAX × 997), do the sum on values 1000 times larger then divide back to your 16 bit scale. 32位将足以存储(INT16_MAX×997),对值的总和大1000倍,然后再分为16位。

Bit shifts are usually very fast: 位移通常非常快:

y = 0xFF3B * (int32_t) x >> 16;

This is probably better written as: 这可能写得更好:

y = (0.997 * 0x10000) * (int32_t)x >> 16;

A good compiler will generate equivalent output. 一个好的编译器会产生等效的输出。

If your integers are signed, the constants should be changed to 0x8000 and 15. 如果您的整数已签名,则常量应更改为0x8000和15。

You probably meant to have some rounding in there, rather than truncating the result to an integer, otherwise the purpose of the operation is really limited. 你可能想要在那里进行一些舍入,而不是将结果截断为整数,否则操作的目的实际上是有限的。

But since you asked the question with that specific formula, it brought to mind that your result set is really coarse. 但是既然你用这个特定的公式提出问题,就会想到你的结果集很粗糙。 For the first 333 numbers, the result is: another_16bit_integer-1. 对于前333个数字,结果为:another_16bit_integer-1。 You can approximate it (maybe even exactly, when not performed in my head) with something like: 您可以通过以下方式对其进行近似(甚至可能是在我头脑中未完成时):

16bit_integer = another_16bit_integer - 1 - (another_16bit_integer/334);

edit: unsigned int, and you handle 0 on your own. 编辑:unsigned int,你自己处理0。

On my platform ( Atmel AVR 8-bit micro-controller, running gcc ) 在我的平台上(Atmel AVR 8位微控制器,运行gcc)

16bit_integer = another_16bit_integer * 0.997;

Takes about 26 instructions. 需要大约26条指令。

16bit_integer = (int16_t) (another_16bit_integer * (int32_t) 997 / 1000);

Takes about 25 instructions. 需要大约25条指令。

Here is a very fast way to do this operation: 这是一种非常快速的方法来执行此操作:

a = b * 0.99609375;

It's similar to what you want, but it's much faster. 它与您想要的类似,但速度快得多。

a  = b;
a -= b>>8;

Or even faster using a trick that only works on little endian systems, like the PIC. 或者甚至更快地使用仅适用于小端系统的技巧,如PIC。

a  = b;
a -= *((int8*)((&b)+1));

Off the top of my head, this comes down to the following assembler on a PIC18: 在我的脑海中,这归结为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];

Precomputed lookup table: 预先计算的查找表:

16bit_integer = products[another_16bit_integer];

That's not going to work so good on the AVR, the 16bit address space is going to be exhausted. 这在AVR上不会那么好用,16位地址空间将会耗尽。

Since you are using an 8 bit processor, you can probably only handle 16 bit results, not 32 bit results. 由于您使用的是8位处理器,因此您可能只能处理16位结果,而不能处理32位结果。 To reduce 16 bit overflow issues I would restate the formula like this: 为了减少16位溢出问题,我会重申这样的公式:

result16 = operand16 - (operand16 * 3)/1000

This would give accurate results for unsigned integers up to 21845, or signed integers up to 10922. I am assuming the the processor can do 16 bit integer division. 这将给出高达21845的无符号整数或高达10922的有符号整数的精确结果。我假设处理器可以进行16位整数除法。 If you cannot then you need to do the division the hard way. 如果你不能那么你需要艰难地进行分工。 Multiplying by 3 can be done by simple shifts & adds, if no multiply instruction exists or if multiplication only works with 8 bit operands. 如果不存在乘法指令或者乘法仅适用于8位操作数,则可以通过简单的移位和相加来乘以3。

Without knowing the exact microprocessor it is impossible to determine how long such a calculation would take. 在不知道确切的微处理器的情况下,不可能确定这样的计算需要多长时间。

On my platform ( Atmel AVR 8-bit micro-controller, running gcc ) 在我的平台上(Atmel AVR 8位微控制器,运行gcc)

16bit_integer = another_16bit_integer * 0.997;

Takes about 26 instructions. 需要大约26条指令。

16bit_integer = (int16_t) (another_16bit_integer * (int32_t) 997 / 1000);

Takes about 25 instructions. 需要大约25条指令。

The Atmel AVR is a RISC chip, so counting instructions is a valid comparison. Atmel AVR是RISC芯片,因此计数指令是有效的比较。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM