我想在我的整数类中实现无符号左旋转。但由于它是一个模板类,可以是任何大小,从128位到更大;因此,我不能使用需要相同大小的临时变量的算法,因为如果类型变得很大,就会发生堆栈溢出(特别是如果这样的函数在调用链中)。
因此,为了解决这个问题,我将其缩小为一个问题:仅使用4位,我必须执行哪些步骤才能旋转32位数字。好吧,如果你考虑一下,一个32位数字包含8组每组4位,因此如果要旋转的位数为4,则将在组
如果要旋转的位数小于4且大于0,则只需保留最后的
以小端二进制表示的数字为
结果是
因此,为了解决这个问题,我将其缩小为一个问题:仅使用4位,我必须执行哪些步骤才能旋转32位数字。好吧,如果你考虑一下,一个32位数字包含8组每组4位,因此如果要旋转的位数为4,则将在组
0和4
,1和5
,2和6
,3和7
之间进行交换,然后进行旋转。如果要旋转的位数小于4且大于0,则只需保留最后的
N
位并开始移位或循环。例如,假设我们有数字0x9CE2
,要向左旋转3位,则应按如下方式操作:以小端二进制表示的数字为
1001 1100 1110 0010
,每个四位数从右到左编号为0到3,我们将称此数字为N
,一组中的位数为B
。[1] x <- N[3] >> 3
x <- 1001 >> 3
x <- 0100
y <- N[0] >> (B - 3)
y <- N[0] >> (4 - 3)
y <- 0010 >> 1
y <- 0001
N[0] <- (N[0] << 3) | x
N[0] <- (0010 << 3) | 0100
N[0] <- 0000 | 0100
N[0] <- 0100
[2] x <- y
x <- 0001
y <- N[1] >> (B - 3)
y <- N[1] >> (4 - 3)
y <- 1110 >> 1
y <- 0111
N[1] <- (N[1] << 3) | x
N[1] <- (1110 << 3) | 0001
N[1] <- 0000 | 0001
N[1] <- 0001
[3] x <- y
x <- 0111
y <- N[2] >> (B - 3)
y <- N[2] >> (4 - 3)
y <- 1100 >> 1
y <- 0110
N[2] <- (N[2] << 3) | x
N[2] <- (1100 << 3) | 0111
N[2] <- 0000 | 0111
N[2] <- 0111
[4] x <- y
x <- 0110
y <- N[3] >> (B - 3)
y <- N[3] >> (4 - 3)
y <- 1001 >> 1
y <- 0100
N[3] <- (N[3] << 3) | x
N[3] <- (1001 << 3) | 0110
N[3] <- 1000 | 0110
N[3] <- 1110
结果是
1110 0111 0001 0100
,十六进制为0xE714
,这是正确的答案;如果您尝试将其应用于任何具有任何精度的数字,则所需的仅是一个类型为形成该大数类型的数组中的任何元素类型的变量。
现在真正的问题是当要旋转的位数大于一个组或大于类型的一半大小时(即大于4位或8位),情况就很复杂了。
通常,我们从最后一个元素向第一个元素移位,以此类推;但现在,在将最后一个元素移动到第一个元素之后,结果必须被重新定位到新位置,因为要旋转的位数大于一个元素(即> 4位
)。移位将开始的起始索引是最后一个索引(在此示例中为3),对于目标索引,我们使用方程式:dest_index = int(bits_count/half_bits) + 1
,其中half_bits
是数字的一半位数,在此示例中half_bits = 8
,因此如果bits_count = 7
,则dest_index = int(7/8) + 1 = 1 + 1 = 2
,这意味着第一次移位的结果必须重新定位到目标索引2 - 这就是我的问题,因为我无法想出一种算法来解决这种情况。
谢谢。