【问题标题】:Implementing BigInteger's multiply...from scratch (and making sure it's O(n^2))实现 BigInteger 的乘法......从头开始(并确保它是 O(n^2))
【发布时间】:2011-08-25 18:33:41
【问题描述】:

作为家庭作业,我正在实现 Karatsuba 的算法,并将其与小学风格的 O(n^2) 大整数乘法算法进行基准测试。

我猜我在这里唯一的选择是将数字带入它们的字节数组表示,然后从那里开始处理它们。

好吧,我被困在这里......当使用 * 运算符时,我不知道如果数字溢出字节乘法或添加进位,我将如何检测/纠正。有任何想法吗?

public static BigInteger simpleMultiply(BigInteger x, BigInteger y){

        //BigInteger result = x.multiply(y);

        byte [] xByteArray = x.toByteArray();
        byte [] yByteArray = y.toByteArray();

        int resultSize = xByteArray.length*yByteArray.length;

        byte [][] rowsAndColumns = new byte[resultSize][resultSize];

        for (int i =0; i<xByteArray.length;i++)
           for (int j=0; j<yByteArray.length;j++){


               rowsAndColumns[i][j] = (byte )(xByteArray[i] * yByteArray[j]); 
               // how would I detect/handle carry or overflow here?               
           }

        return null;
    }

【问题讨论】:

  • 两个月前我在这里写了一个big-number tutorial,其中还包括一个乘法。它不使用字节,而是使用 int 值(在 0 ... 1000000000 范围内),将其乘以 long 以避免溢出。
  • @Paulo:谢谢,但我需要 1000 位的整数。

标签: java bytearray biginteger


【解决方案1】:

字节相乘的结果是 2 个字节。您必须使用低位字节作为结果,使用高位字节作为进位(溢出)。

我还建议您注意字节的符号。由于 Java 中的字节是有符号的,因此您必须要么只使用它们的低 7 位,要么将它们转换为整数并在相乘之前更正符号。

你会想要一个像这样的循环:

        for (int i =0; i<xByteArray.length;i++)
           for (int j=0; j<yByteArray.length;j++){
               // convert bytes to ints
               int xDigit = xByteArray[i], yDigit = yByteArray[j];
               // convert signed to unsigned
               if (xDigit < 0)
                   xDigit += 256;
               if (yDigit < 0)
                   yDigit += 256;
               // compute result of multiplication
               int result = xDigit * yDigit;
               // capture low order byte
               rowsAndColumns[i][j] = (byte)(result & 0xFF);
               // get overflow (high order byte)
               int overflow = result >> 8;
               // handle overflow here
               // ...
           }

【讨论】:

  • 什么是低位/高位字节?每个字节的低7位是低位字节?
  • 当您将 2 个单独的数字(例如 9 * 9)相乘时,您会得到 2 位的结果 (81)。在此示例中,8 将是高位数字,1 将是低位数字。如果将 2 个单独的字节相乘(例如 0xFF * 0xFF),则得到 2 字节的结果(0xFE01)。在这个例子中,0xFE 是高位字节,0x01 是低位字节。
  • 你能解释一下 rowsAndColumns[i][j] = (byte)(result & 0xFF);和 int 溢出 = 结果 >> 8;?我不熟悉字节算术/移位,我想了解逻辑。
  • 如果你对位运算不熟悉,我推荐一个快速教程,比如cprogramming.com/tutorial/bitwise_operators.html
  • 在将结果值分配给行和列后,我不明白您是如何处理溢出的,是否应该为下一次迭代存储它?
【解决方案2】:

避免溢出的最好方法是一开始就不让它发生。使用更高宽度的数字进行所有计算以避免出现问题。

例如,假设我们有 256 个基数,每个数字都存储为单个无符号字节。

d1 = (int) digits[i] //convert to a higher-width number
d2 = (int) digits[j]
product = d1*d2  //ints can handle up to around 2^32. Shouldn't overflow w/ 256*256
result = product % 256
carry  = product / 256

您可能会很想将除以 2 的幂转换为位运算,但这并不是必需的。

【讨论】:

  • 这不能解决携带问题。
  • 它确实如此,只要您用于计算的类型(在我的示例中,int)是用于存储数字的类型的两倍(在这种情况下为 bytes )。这就是在四年级时,您使用一位数字存储数字但使用两位数字进行乘法的方式。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-12
  • 1970-01-01
  • 1970-01-01
  • 2019-10-10
相关资源
最近更新 更多