ale*_*lex 15 c performance digits
我必须将数字拆分成数字才能在LCD上显示.现在我使用以下方法:
pos = 7;
do
{
LCD_Display(pos, val % 10);
val /= 10;
pos--;
} while (pos >= 0 && val);
Run Code Online (Sandbox Code Playgroud)
这种方法的问题在于MSP430微控制器上的除法和模运算非常慢.有没有替代这种方法的东西,既不涉及分裂,也不会减少操作次数?
注意:我不能使用任何库函数,例如itoa
.这些库很大,而且功能本身也非常耗费资源(在循环次数和RAM使用方面).
Guf*_*ffa 13
您可以在具有预定义基数10值的循环中进行减法.
我的C有点生疏,但是像这样:
int num[] = { 10000000,1000000,100000,10000,1000,100,10,1 };
for (pos = 0; pos < 8; pos++) {
int cnt = 0;
while (val >= num[pos]) {
cnt++;
val -= num[pos];
}
LCD_Display(pos, cnt);
}
Run Code Online (Sandbox Code Playgroud)
是的,还有另一种方式,最初由Terje Mathiesen发明(至少是AFAIK).而不是除以10,你(有点)乘以倒数.当然,诀窍在于整数中你不能直接表示倒数.为了弥补这一点,您使用缩放整数.如果我们有浮点数,我们可以用以下内容提取数字:
input = 123
first digit = integer(10 * (fraction(input * .1))
second digit = integer(100 * (fraction(input * .01))
Run Code Online (Sandbox Code Playgroud)
...等等,根据需要提供多个数字.要用整数来做这个,我们基本上只是将它们缩放2 32(并且每个向上舍入,因为我们将使用截断数学).在C中,算法如下所示:
#include <stdio.h>
// here are our scaled factors
static const unsigned long long factors[] = {
3435973837, // ceil((0.1 * 2**32)<<3)
2748779070, // ceil((0.01 * 2**32)<<6)
2199023256, // etc.
3518437209,
2814749768,
2251799814,
3602879702,
2882303762,
2305843010
};
static const char shifts[] = {
3, // the shift value used for each factor above
6,
9,
13,
16,
19,
23,
26,
29
};
int main() {
unsigned input = 13754;
for (int i=8; i!=-1; i--) {
unsigned long long inter = input * factors[i];
inter >>= shifts[i];
inter &= (unsigned)-1;
inter *= 10;
inter >>= 32;
printf("%u", inter);
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
循环中的操作将直接映射到大多数32位处理器上的指令.典型的乘法指令将采用2个32位输入,并产生64位结果,这正是我们所需要的.它通常比分割指令快一点.在典型的情况下,一些操作将(或至少在某种程度上可以)用汇编语言消失.例如,在我完成的情况下inter &= (unsigned)-1;
,在汇编语言中,您通常只能使用存储结果的低32位寄存器,并忽略保存高32位的任何内容.同样,这inter >>= 32;
意味着我们使用高32位寄存器中的值,并忽略低32位寄存器.
例如,在x86汇编语言中,这就像是:
mov ebx, 9 ; maximum digits we can deal with.
mov esi, offset output_buffer
next_digit:
mov eax, input
mul factors[ebx*4]
mov cl, shifts[ebx]
shrd eax, edx, cl
mov edx, 10 ; overwrite edx => inter &= (unsigned)-1
mul edx
add dl, '0'
mov [esi], dl ; effectively shift right 32 bits by ignoring 32 LSBs in eax
inc esi
dec ebx
jnz next_digit
mov [esi], bl ; zero terminate the string
Run Code Online (Sandbox Code Playgroud)
目前,我已经欺骗了一点,并在每个表(factors
和shifts
)的开头假设一个额外的项目编写代码.这不是严格必要的,但是以浪费8个字节的数据为代价简化了代码.这也很容易取消,但我暂时没有打扰.
在任何情况下,在相当多的缺乏专用分区硬件的中低端处理器上,取消该部门会使这一点变得更快.