我可以访问一个在其上运行C风格脚本语言的工具。它可以声明和使用char
,int
和double
的变量或数组,但不能使用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
的位数)并将输出标志设置为其值,但这不能通过位移来完成,因为我不喜欢没有它。
移位值相当于乘以/除以2(使用整数数学):
a / 2 equivalent to a >> 1
a * 2 equivalent to a << 1
您需要检查脚本语言是否进行整数数学运算(或使用floor()
或int()
或trunc()
或者语言提供的语言)。
要小心溢出,如果脚本语言使用float而不是int来表示数字,你可能会发现大数字的奇怪行为。
关于签署的另一个警告。如果你必须处理负数,向左移动会更复杂。
你可以运行几个测试来检查整数的大小吗?它肯定会帮助您避免问题。
左移1等于乘以2,右移1等于(整数)除以2.因此,左移3等于乘以8(因为它是23)。
#include <stdio.h>
int main() {
int a = 17 << 4;
int b = 17 * 16;
if (a == b) {
printf("%i\n", 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;
}
右移是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。您还可以将2D的数组移位1次以上,或者多次移1次。该方法也可以应用于左移