我通过将一些C ++函数移植到.NET的BigInteger来独立研究位移。我注意到当我移动BigInteger时,虚空被填充了。
我认为这与以二元赞美形式存储的负数有关。
BigInteger num = -126;
compactBitsRepresentation = (uint)(int)(num << 16);
以下是班次之后发生的事情(最重要的第一位)
10000010 will be shifted 16
11111111100000100000000000000000 was shifted 16
我是否总是期望类似的位移操作以这种方式运行?这是否与OpenSSL等“bigNumber”的不同语言和实现一致?
答案 0 :(得分:1)
来自BigInteger.LeftShift
operator docs:
与使用整数基元的按位左移操作不同 LeftShift方法保留原始BigInteger值的符号。
所以.NET保证你看到的行为。
我对bignum库并不熟悉,但OpenSSL的BIGNUM BN_lshift()函数的文档说:
BN_lshift()
向左移位n位并将结果放在r(“r = a * 2 ^ n”)中。BN_lshift1()
将左移一个并将结果放在r(“r = 2 * a”)中。
由于操作是以2的幂乘法定义的,如果将得到的BIGNUM转换为2的补码数(我不知道BIGNUM如何在内部表示数字),那么你会看到类似于.NET的行为
如果其他bignum库表现相似,我不会感到惊讶,但如果你想依赖行为,你真的需要检查文档。但是,由于移位非常类似于乘法或除以2的幂,所以通过使用适当的乘法或除法而不是移位,您可能可以获得“便携”行为。那么你需要确保的是你可以将转换转换为二进制补码表示(这个问题实际上与转换操作的行为无关)。
答案 1 :(得分:1)
我是否总是期望类似的位移操作以这种方式运行?
如果所讨论的数字格式使用两个补码来表示负数(并且很多都是),则应该这样做。要形成数字的二进制补码,可以反转所有位并添加一个,例如:
23 is represented as 00010111
-23 is represented as 11101001 (that is, 11101000 + 1)
此外,当您将类型转换为更大的类型时,该值通常是符号扩展的,即最左边的位扩展为较大类型的额外位。这保留了数字的符号。
所以是的,数字表示通常用数字值“填充”为1是很常见的。
答案 2 :(得分:0)
10000010 --> 11111111 11111111 11111111 10000010
左边是1,因为数字是负数。
现在左移只是从右边插入0并从左边掷出位:
11111111 11111111 11111111 10000010 << 16 -->
11111111 10000010 00000000 00000000