0

我有以下我试图理解的代码。

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 类有助于处理大整数。构造函数用于将 long 值分配给 Big Integer 对象。我知道名为 value 的变量被复制到 uint[] 数据数组(允许的最大位数为 maxLength)。

我无法完全理解如何检查下溢和上溢。我了解条件 if(tempVal > 0) 和 else if(tempVal < 0) 但为什么在下溢和上溢的情况下数据的最高数组索引与 0x80000000 相加?(为什么在上溢/下溢的情况下不为0xFFFFFFFF?如果数字比允许的最大数量多/少1,则会导致上溢/下溢)

此外,将 long 值传递给构造函数是否会限制 BigInteger 的整体大小(其最大值可以与 long 变量的最大值相同)?

4

1 回答 1

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 的方法(例如进行算术运算)。例如,它是否允许两个 BigInteger 相乘?

于 2013-06-08T19:31:29.750 回答