通过移位、反转和加 +/- 1 构造十六进制数

Constructing a hex number by shifting, inverting and adding +/- 1

我正在尝试将数字 0xFD00 保存在寄存器中(MIC-1 架构)。有寄存器:

我可以进行左移、右移和反转。也可以添加类似 SMASK + SMASK 或 AMASK + (-1) 的值。我可以用 inverse(AMASK) 得到 0xF000,但我不确定如何在没有太多步骤的情况下得到 0xFD00。

迄今为止最高效的序列是@Falk Hüffner's answer,3 个操作。 (尽管它涉及一个 +,它不加 +1 或 -1,或者不给它自己加一个值)。
这个答案显示了一种方法,它采用问题标题中明确提到的 4 种操作。


0xFD 是 0b11111101。所以它有一堆连续的位,还有一个杂散的设置位。一种简单的方法是

  • 从 all-ones(-1~00 - 1)开始
  • 左移2得到...11111100
  • 加 1 得到 ...11111101 (0x...FD)
  • 移位到寄存器的顶部,移入低位 0 并移出高位 1,留下 0xFD 在顶部,有 8 个低位零。

我不了解 MIC-1,但从您的描述来看,它似乎可以执行这些步骤。如果一次只能移动 1 个位置,则总共需要 2 + 8 条移位指令。可能有其他方法可以更有效地构造此常量,也许是我没有想到的东西,或者可能是机器具有的某些功能。


利用AMASK / SMASK和add / sub carry-propagation的方式可以分别翻转1 / 0位的序列,以及Aki的观察~0xfd00 = 0x02ff,我们可以做到以下几点:

initial AMASK = 0x00FF

AMASK += 1     (0x0100)
AMASK += AMASK (0x0200)  (left shift)
AMASK += SMASM (0x02FF)
NOT AMASK      (0xFD00)

请参阅 https://catonmat.net/low-level-bit-hacks,了解您可以使用按位运算进行的各种恶作剧的精彩介绍。 (尽管其中许多还需要 AND、OR 或 XOR。例如,通过 x &= (x-1) 清除最低设置位)


(相关:x86 SIMD 向量的 What are the best instruction sequences to generate vector constants on the fly?:类似的问题,您可以廉价地即时生成 -1 而无需从内存加载,并通过左移等各种其他指令提供它,( SSSE3) 绝对值。但只对短序列​​值得做,否则只需从内存或 mov-immediate 加载到整数寄存器和 movd xmm0, eax)


十六进制只是一种在文本中表示数字的方式,例如ASCII。 你可以称之为序列化格式。

0xFD00 只是 64768(基数 10)或 0b1111110100000000(基数 2)的另一种写法。因此,您只是在移位和 inc/dec 之外的寄存器中构造 一个数字 。假设你的 bit-shifts 乘以/除以 2,而不是 10 或 16,这些是 binary 运算,所以这是一个二进制数。用像十六进制这样的紧凑格式来表达所需的二进制数只是很方便,但在任何时候你实际上都不需要十六进制,比如一串 base-16 ASCII 数字。

当你在寄存器中构造它时,它不是一个“十六进制数”,它只是一个数字。 如果有的话,它是二进制的。

0xFD00 的倒数 == 0b00000010 11111111 = 0x02ff

这可以通过 SMASK = 0x00FF * 3 + 2 或简单地使用 SMASK | 来实现(1 << 9),如果可用的话。

a = smask
b = smask << 1
a = a + b
a++
a++
return ~a

假设加法可以用两个寄存器实现,而不仅仅是一个常量,左移只是删除从 16 位字中移出的位:

t = ~SMASK    // 0xff00
return t + (t << 1)

如果可以通过任意常数而不仅仅是 1 进行移位,则另一种选择是

t = SMASK
t += -1
t += -1
t <<= 8