我有以下功能:
uint16_t foo(uint8_t input)
{
uint16_t N = 38;
if (!(input&1))
{
N = 0;
}
else
{
if ((input&2) >> 1)
{
N = ~N;
}
}
return N;
}
我希望在没有ifs
的情况下重写它,就像内联函数一样,将38
转换为0,38
或65497
给定input
和仅使用标准C比特操作。
关键不在于编译器可以内联函数,或者函数是快速的,而只是为了摆脱分支并保持恒定时间而不管input
是什么。
第一个if
很简单:
uint16_t c = ((input&1)^1)-1;
N &= c;
但是我找到一些简单的方法去做条件否定时遇到了麻烦。
答案 0 :(得分:5)
使用表格查找。
uint16_t foo(uint8_t input) {
int index= input & 0x3;
const uint16 table[4]= {0,~38,0,38};
return table[index];
}
答案 1 :(得分:3)
要保证运行时和平衡代码,必须进行汇编。由于MSP430汇编器并不复杂,因此不会出现太大问题。请注意,乘法等操作可能由不常量运行时的函数执行。
避免分支是没有意义的。相反,您应该平衡执行路径,例如使用NOP(无操作)。 MSP430用户指南包括指令时序。请注意,时序是固定的,这与ARM等较大的CPU不同,后者依赖于流水线和内存时序。
一般说明:通过CPU周期进行计时通常是一个坏主意。像MSP430这样的现代MCU提供内部定时器和与其他外设(如ADC)的连接,以触发例如转换具有高度准确的时间。它们可以生成中断,因此CPU可以准备下一个值或读取样本而无需关心代码的运行时间(除非它花费的时间太长)。
使用CPU来禁止例如中断,因为这会打击任何时间。这使得维护这样一个系统成为一场噩梦。
答案 2 :(得分:2)
如果我以正确的方式阅读您的代码,则说明如下:
uint16_t foo1(uint8_t input)
{
uint16_t N = 38;
uint16_t bit0 = input & 1;
uint16_t nbit0 = bit0 ^ 1;
uint16_t bit1 = (input & 2) >> 1;
uint16_t nbit1 = bit1 ^ 1;
N = nbit0 * ( bit1 * ~N + nbit1 * N);
return N;
}
随意摆脱变量。它们只是为了便于阅读。
答案 3 :(得分:2)
这应该有用。
#include<stdio.h>
int main(){
int input;
scanf("%d", &input);
int N = (input&1)*(((input&2)*32729)+(38+((input&2)>>1)));
printf("%d\n", N);
}
答案 4 :(得分:2)
7次操作,没有乘法,建立在njuffa的评论之上:
uint16_t bar(uint8_t input)
{
return (0-(input&1)) & (38^(0-((input>>1)&1)));
}