我有以下一段代码,我想要理解。
Big Integer类(自定义,而不是标准类)具有以下成员:
private const int maxLength = 2000;
private uint[] data = null; // stores bytes from the Big Integer
public int dataLength; // number of actual chars used
构造函数如下:
public BigInteger(long value)
{
data = new uint[maxLength];
long tempVal = value;
// copy bytes from long to BigInteger without any assumption of
// the length of the long datatype
dataLength = 0;
while(value != 0 && dataLength < maxLength)
{
data[dataLength] = (uint)(value & 0xFFFFFFFF);
value >>= 32;
dataLength++;
}
if(tempVal > 0) // overflow check for +ve value
{
if(value != 0 || (data[maxLength-1] & 0x80000000) != 0)
throw(new ArithmeticException("Positive overflow in constructor."));
}
else if(tempVal < 0) // underflow check for -ve value
{
if(value != -1 || (data[dataLength-1] & 0x80000000) == 0)
throw(new ArithmeticException("Negative underflow in constructor."));
}
基本上,BigInteger类有助于操作大整数。构造函数用于为Big Integer对象分配long值。我知道名为value的变量被复制到uint []数据数组(允许的最大位数为maxLength)。
我无法完全理解如何检查下溢和溢出。我理解条件if(tempVal&gt; 0)和if if(tempVal&lt; 0)但是为什么在下溢和溢出的情况下,数据的最高数组索引与0x80000000相关? (为什么在溢出/下溢的情况下不是0xFFFFFFFF?如果数字比允许的最大数量多1个/小,则会导致溢出/下溢)
另外,没有将long值传递给构造函数限制BigInteger的整体大小(其最大值可以与long变量的最大值相同)?
答案 0 :(得分:1)
对于C#中的int,0x80000000处的位(即最高位)是符号位。换句话说,如果它包含1,则数字为负数。包含位0xffffffff的int将被解释为包含-1。在整数运算期间,携带到该位的数字将表示溢出条件,这可能是检查所依据的。
类似地,对于任何正数,符号位都包含0,因此如果您希望该数字为负数,但该位包含0,那么您就知道该位必须发生一些溢出。实际上,表示负数的方式,实际数字左边的每个位都设置为1.例如,3表示为0x00000003(左边的所有内容都是0)而-3表示为0xfffffffd(所有内容都是左边是1)。
代码基本上会用相同的约定填充整个数组。在其中存储一个正数,它将填充前几个元素,将其他所有元素都清零。传入一个负数,然后将数字放在前几个元素中,然后用0xffffffff填充几乎整个数组,从而保留最左边的位(即最后一个元素的最左边的位)的约定。数组)是符号位。在数字之后用-0xffffffff填充整个数组,因为C#中的右移运算符保留了符号位:如果它右移一个负数,它将向左填充所有的1而不是0。
因此,考虑这些测试的方法是他们检查数组的符号位(最后一个元素的最左边的位)是否正确。
顺便说一句,我不相信有任何方法会触发异常条件,因此我怀疑在编写代码时可能已将这些测试用于调试目的,然后将其留下。
我对代码的阅读是,当你建议将long值传递给构造函数时,你是正确的,这限制了BigInteger中存储的值的整体大小。但是,您只显示了构造函数的代码。我猜测该类包含其他方法(例如,算术),可能会导致更大的值被放入BigInteger。例如,它是否允许两个BigIntegers相乘?