【发布时间】:2011-02-28 06:58:46
【问题描述】:
我正面临一个相当特殊的问题。我正在为不支持按位运算的架构开发编译器。但是,它处理带符号的 16 位整数算术,我想知道是否可以仅使用以下方式实现按位运算:
- 加法 (c = a + b)
- 减法 (c = a - b)
- 除法(c = a / b)
- 乘法 (c = a * b)
- 模数 (c = a % b)
- 最小值 (c = min(a, b))
- 最大值 (c = max(a, b))
- 比较(c = (a )
- 跳跃(goto、for 等)
我希望能够支持的按位运算是:
- 或 (c = a | b)
- 和(c = a & b)
- 异或 (c = a ^ b)
- 左移 (c = a )
- 右移 (c = a >> b)
- (所有整数都有符号,所以这是个问题)
- 有符号移位 (c = a >>> b)
- 补码 (a = ~b)
- (已经找到解决方案,见下文)
通常情况正好相反;如何使用按位 hack 实现算术优化。但是在这种情况下不是。
在这种架构上,可写内存非常稀缺,因此需要按位运算。按位函数本身不应使用大量临时变量。但是,常量只读数据和指令内存是丰富的。附带说明一下,跳转和分支并不昂贵,并且所有数据都可以轻松缓存。跳转花费的周期是算术(包括加载/存储)指令的一半。换句话说,以上所有支持的函数都花费了单次跳转周期的两倍。
一些可能有帮助的想法:
我发现您可以使用以下代码进行一个补码(否定位):
// Bitwise one's complement
b = ~a;
// Arithmetic one's complement
b = -1 - a;
我还记得在除以 2 的幂时的旧移位技巧,因此 按位移位 可以表示为:
// Bitwise left shift
b = a << 4;
// Arithmetic left shift
b = a * 16; // 2^4 = 16
// Signed right shift
b = a >>> 4;
// Arithmetic right shift
b = a / 16;
对于其余的按位运算,我有点不知所措。我希望这种架构的架构师能够提供位操作。
我还想知道是否有一种快速/简单的方法可以在不使用内存数据表的情况下计算 2 的幂(用于移位操作)。一个天真的解决方案是跳入乘法领域:
b = 1;
switch (a)
{
case 15: b = b * 2;
case 14: b = b * 2;
// ... exploting fallthrough (instruction memory is magnitudes larger)
case 2: b = b * 2;
case 1: b = b * 2;
}
或 Set & Jump 方法:
switch (a)
{
case 15: b = 32768; break;
case 14: b = 16384; break;
// ... exploiting the fact that a jump is faster than one additional mul
// at the cost of doubling the instruction memory footprint.
case 2: b = 4; break;
case 1: b = 2; break;
}
【问题讨论】:
-
只是出于好奇,如今没有布尔运算符,CPU 究竟如何构建?这是十进制机器吗?
-
这是我最近在 Stack Overflow 上看到的最有趣的问题。
-
如果运算成本的关系是准确的,这确实是一台非常奇怪的机器——整数除法与乘法相同的速度?我的猜测可能是由离散逻辑构建的,也许就像他们在早期太空探测器中使用的 NASA 定制构建计算机?
-
为了平息你的好奇心,也许也让你失望,这不是美国宇航局太空探测器的东西。 (如果我说是,我必须杀了你)。实际上,这种架构来自一款名为 RoboCom 的游戏。游戏有一个有趣、简单的想法;你为一个机器人编写程序集,然后它试图超越其他机器人。每个机器人的内存非常稀缺(大约 40 字节),我想编写一个高级编译器,该编译器还可以提供稍微昂贵的 bitpacker 来压缩更多信息。可以通过包含 SET 操作数的数据库来模拟常量内存和表。程序员的游戏!
-
如果有什么好处的话,IBM 1620 不仅没有内置的二进制运算符,它甚至不能添加。加法必须通过查表来完成。另一方面,由于它是一个十进制机器,它可以处理任意精度的十进制数(在商业中很有用)。
标签: bitwise-operators discrete-mathematics compiler-optimization