使用类似C的脚本语言实现位移运算符

时间:2014-03-11 15:11:05

标签: c bit-manipulation operators bit-shift

我可以访问一个在其上运行C风格脚本语言的工具。它可以声明和使用charintdouble但不是float的变量或数组。它允许标准C逻辑和加法,减法,除法和乘法的操作数。它没有sizeof()等有用功能,也没有任何位移操作符<<>>

我试图通过两个二进制输出端口发送double值。每个都可以设置为高或低。

我想我应该通过使用逐位AND比较器对双值进行位移掩码来实现这一点。但是我不能这样做,因为不存在位移操作符。然后,我将使用一个输出端口作为时钟,第二个作为同步数据线。

例如,使用值为6的输入字节(0000 0110)。数据将如下输出,X表示“时钟”向下笔划的读取值:

*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的位数)并将输出标志设置为其值但这不能完成有点移位,因为我没有它。

4 个答案:

答案 0 :(得分:1)

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

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

您需要检查脚本语言是否进行整数数学运算(或使用floor()int()trunc()或使用语言提供的语言。

请注意溢出,如果脚本语言使用float而不是int来表示数字,那么您可能会发现大数字的奇怪行为。

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

你可以运行几个测试来检查整数的大小吗?它肯定会帮助你避免问题。

答案 1 :(得分:0)

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

#include <stdio.h>

int main() {
  int a = 17 << 4;
  int b = 17 * 16;

  if (a == b) {
    printf("%i\n", b);
  } else {
    puts("false");
  }
}

输出

272

答案 2 :(得分:0)

假设您尝试检索的测量值确实是双倍的:如果您知道测量的允许范围,我会将它们乘以系数0xFFFFFFFF/MAX_RANGE因子,以得到0到最大值之间的值。

然后你可以做

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;
 }

这比尝试使用没有掩码和移位的浮点数的按位表示更好。

答案 3 :(得分:0)

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

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;
}

右移是a lot trickier to implement,只有加法/减法。如果您不想使用慢速除法,则可以使用查找表

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。此方法也可以应用于左移