位操作-在类似c的脚本语言中实现位移位操作符



我可以使用一个在上面运行c风格脚本语言的工具。它可以声明和使用charintdouble的变量或数组,但不能声明和使用float。它允许标准C逻辑和加、减、除、乘的操作数。它没有sizeof()这样有用的函数,也没有<<>>这样的位移运算符。

我试图让它在两个二进制输出端口上发送double值。

可设置为High或low。

我认为我应该通过使用位与比较器对双值进行位移位屏蔽来做到这一点。然而,我不能这样做,因为位移位操作符不存在。然后,我将使用一个输出端口作为时钟,另一个作为同步数据线。

例如使用value = 6(0000 0110)的输入字节。数据将如下所示输出,其中X表示'clock' down stroke上的读取值:

*Clock,  Input
* 0,     0
* 1,     0 X
* 0,     0
* 1,     1 X
* 0,     0
* 1,     1 X
* 0,     0
* 1,     0 X
* 0,     0
* 1,     0 X
* 0,     0
* 1,     0 X
* 0,     0
* 1,     0 X
* 0,     0
* 1,     0 X
* 0,     0

所以我需要一种方法通过双位逐位迭代(不确定仪器使用多少位double)并将输出标志设置为其值,但这不能用位移来完成,因为我没有它。

移动一个值相当于乘/除2(使用整数数学):

 a / 2   equivalent to  a >> 1 
 a * 2   equivalent to  a << 1 

您需要检查脚本语言是否执行整数数学(或使用floor()int()trunc()或语言提供的任何方法)。

也要小心溢出,如果脚本语言使用float而不是int来表示数字,你可能会看到大数字的奇怪行为。

关于签名的另一个警告。如果你必须处理负数,向左移动会更复杂。

您可以运行几个测试来检查整数的大小吗?

A左移1等于A乘以2,A右移1等于(整数)除以2。因此,左移3等于乘以8(因为它是23)。

#include <stdio.h>
int main() {
  int a = 17 << 4;
  int b = 17 * 16;
  if (a == b) {
    printf("%in", b);
  } else {
    puts("false");
  }
}

输出
272

假设您试图检索的测量值是真正的双精度:如果您知道测量值的允许范围,我会将它们乘以0xFFFFFFFF/MAX_RANGE因子,以给您一个介于0和int max之间的值。

然后你可以做

long int value = double*FACTOR;
for (i=0;i<32;i++) {
    long int nextval = value / 2;
    char bit = value - (nextval * 2);
    //send bit here
    value = nextval;
 }

这将比尝试在没有掩码和移位的情况下使用浮点数的按位表示要好。

位移位就像乘法或除法一样,所以向左/向右移动N位的最简单方法是乘以/除以2N

const unsigned int SHIFT_BY[] = { 1U, 2U, 4U, 8U, 16U, 32U, 64U, 128U, 256U, 512U,
    1024U, 2048U, 4096U, 8192U, 16384U, 32768U, 65536U, 131072U, 262144U, 524288U,
    1048576U, 2097152U, 4194304U, 8388608U, 16777216U, 33554432U, 67108864U,
    134217728U, 268435456U, 536870912U, 1073741824U, 2147483648U};
unsigned int lshift(unsigned int x, unsigned int numshift)
{
    return x*SHIFT_BY[numshift];
}
unsigned int rshift(unsigned int x, unsigned int numshift)
{
    return x/SHIFT_BY[numshift];
}

但是对于小的移位步骤或没有除法/乘法的架构来说,这是无效的。在这种情况下,只需将数字相加,因为它相当于将其乘以2,这可能会提高性能一点

unsigned int lshift(unsigned int x, unsigned int numshift)
{
    for (i = 0; i < numshift; i++)
        x += x;
    return x;
}

右移在只有加法/减法的情况下实现起来要棘手得多。如果你不想使用慢除法,那么你可以使用查找表

unsigned int rshift1(unsigned int x)
{
    const unsigned int RSHIFT1[] = { 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7 };
    assert(x < 16);
    retrn RSHIFT1[x];
}
上面的

只是一个简单的4位LUT,移位1。如果您愿意/可以,可以使用更大的LUT。你也可以实现移动超过1作为一个2D数组,或通过移动1多次。此方法也可以应用于左移

最新更新