为什么不使用二进制补码进行任意精度整数的减法?
Why not use two's compliment for subtraction in arbitrary precision integer?
Java 的 BigInteger class 使用以下代码从较大的数字中减去较小的数字:
private static int[] subtract(int[] big, int[] little) {
int bigIndex = big.length;
int result[] = new int[bigIndex];
int littleIndex = little.length;
long difference = 0;
// Subtract common parts of both numbers
while (littleIndex > 0) {
difference = (big[--bigIndex] & LONG_MASK) -
(little[--littleIndex] & LONG_MASK) +
(difference >> 32);
result[bigIndex] = (int)difference;
}
// Subtract remainder of longer number while borrow propagates
boolean borrow = (difference >> 32 != 0);
while (bigIndex > 0 && borrow)
borrow = ((result[--bigIndex] = big[bigIndex] - 1) == -1);
// Copy remainder of longer number
while (bigIndex > 0)
result[--bigIndex] = big[bigIndex];
return result;
}
我的问题是,在 little
上简单地执行 ~x+1
而不更改符号的值并将其添加到 big
不是更直接吗?这会不会特别慢?如果是,为什么?
n
位整数的 2 补码表示实际上是惯例,等于或大于 Math.pow(2,n-1)
的无符号整数值 b 不表示存储的值,而是表示值 b-(Math.pow(2,n-1)+1)
,这是负数。由于计算机现在执行环绕算术(意思是 a+b
实际上计算 (a+b) % Math.pow(2, n)
,基本算术在此约定中产生正确的结果。
如果您现在转到 BigIntegers,您希望避免这种情况。您不想要最大整数值 Math.pow(2,n-1)-1
,高于该值的数字突然变为负数。而且你不需要包装算术,你想要真正的整数算术。二进制补码表示绑定到可用整数的特定范围。
大整数存储在 "digits" 的字符串中,其中最高有效位以上的数字被称为零。从理论上讲,您可能会找到一些创造性的方式来存储整数,方法是定义最上面存储的所有位都应该等于存储的最上面的位,然后所有负数 -b
都存储为 Infinity-b
或其他东西,但这会使事情在很多方面变得非常复杂。所以使用符号和幅度存储要容易得多,即使它可能需要更多的存储空间。
Java 的 BigInteger class 使用以下代码从较大的数字中减去较小的数字:
private static int[] subtract(int[] big, int[] little) {
int bigIndex = big.length;
int result[] = new int[bigIndex];
int littleIndex = little.length;
long difference = 0;
// Subtract common parts of both numbers
while (littleIndex > 0) {
difference = (big[--bigIndex] & LONG_MASK) -
(little[--littleIndex] & LONG_MASK) +
(difference >> 32);
result[bigIndex] = (int)difference;
}
// Subtract remainder of longer number while borrow propagates
boolean borrow = (difference >> 32 != 0);
while (bigIndex > 0 && borrow)
borrow = ((result[--bigIndex] = big[bigIndex] - 1) == -1);
// Copy remainder of longer number
while (bigIndex > 0)
result[--bigIndex] = big[bigIndex];
return result;
}
我的问题是,在 little
上简单地执行 ~x+1
而不更改符号的值并将其添加到 big
不是更直接吗?这会不会特别慢?如果是,为什么?
n
位整数的 2 补码表示实际上是惯例,等于或大于 Math.pow(2,n-1)
的无符号整数值 b 不表示存储的值,而是表示值 b-(Math.pow(2,n-1)+1)
,这是负数。由于计算机现在执行环绕算术(意思是 a+b
实际上计算 (a+b) % Math.pow(2, n)
,基本算术在此约定中产生正确的结果。
如果您现在转到 BigIntegers,您希望避免这种情况。您不想要最大整数值 Math.pow(2,n-1)-1
,高于该值的数字突然变为负数。而且你不需要包装算术,你想要真正的整数算术。二进制补码表示绑定到可用整数的特定范围。
大整数存储在 "digits" 的字符串中,其中最高有效位以上的数字被称为零。从理论上讲,您可能会找到一些创造性的方式来存储整数,方法是定义最上面存储的所有位都应该等于存储的最上面的位,然后所有负数 -b
都存储为 Infinity-b
或其他东西,但这会使事情在很多方面变得非常复杂。所以使用符号和幅度存储要容易得多,即使它可能需要更多的存储空间。