我已经编写了一些代码来繁殖真正的长数字。想知道是否有更有效的方法来做到这一点?
这是我现在如何做到的。基本上实现了典型的长乘法'技术
internal enum Digit
{
Zero = 0,
One,
Two,
Three,
Four,
Five,
Six,
Seven,
Eight,
Nine
}
public class NumbersWhiz
{
public string Add(string Augend, string Addend)
{
string longerNum = (Augend.Length > Addend.Length == true) ? Augend : Addend;
string shorterNum = (Addend.Length < Augend.Length == true) ? Addend : Augend;
int longerLen = (Augend.Length > Addend.Length == true) ? Augend.Length : Addend.Length;
int shorterLen = (Addend.Length < Augend.Length == true) ? Addend.Length : Augend.Length;
//Pad the shorter number initially with zeros to match length of longer number
int deltaLen = longerLen - shorterLen;
string numTwoZeroed = new String('0', deltaLen);
string numTwo = numTwoZeroed.Insert(deltaLen, shorterNum);
string numOne = longerNum;
string result = new String('0', longerLen);
StringBuilder resultBuilder = new StringBuilder(result);
bool carryForward = false;
for (int index = longerLen; index > 0; index--)
{
int augend = Convert.ToInt32(numOne.Substring(index - 1, 1));
int addend = Convert.ToInt32(numTwo.Substring(index - 1, 1));
int sum = (carryForward == true) ? 1 : 0;
sum = sum + augend + addend;
carryForward = ((sum > 9) == true) ? true : false;
int reminder = sum % 10;
resultBuilder[index - 1] = Convert.ToChar(reminder.ToString());
}
if(carryForward)
resultBuilder.Insert(0, '1');
return resultBuilder.ToString();
}
public string Multiply(string Multiplicand, string Multiplier)
{
int resultLen = Multiplicand.Length + Multiplier.Length;
string totalSum = new String('0', resultLen);
for (int index = Multiplier.Length; index > 0; index--)
{
int multiplierDigit = Convert.ToInt32(Multiplier.Substring(index - 1, 1));
string product = Multiply(Multiplicand, (Digit)multiplierDigit);
product += new String('0', Multiplier.Length - index);
totalSum = Add(totalSum, product);
}
return totalSum;
}
string Multiply(string Multiplicand, Digit MultiplierDigit)
{
int multiplier = (int)MultiplierDigit;
if (multiplier == 0)
return "0";
int carry = 0;
bool carryForward = false;
int len = Multiplicand.Length;
int productLen = len + 1;
string result = new String('0', productLen);
StringBuilder resultBuilder = new StringBuilder(result);
for (int index = len; index > 0; index--)
{
int multiplicandDigit = Convert.ToInt32(Multiplicand.Substring(index - 1, 1));
int product = (multiplicandDigit * multiplier) + carry;
carryForward = ((product > 9) == true) ? true : false;
int reminder = product % 10;
carry = (product - reminder) / 10;
resultBuilder[index] = Convert.ToChar(reminder.ToString());
}
if (carryForward)
resultBuilder[0] = Convert.ToChar(carry.ToString());
return resultBuilder.ToString();
}
}
答案 0 :(得分:3)
嗯,是的。有更高级的乘法方法。
一种快速简便的加速算法的方法是从基数10(也就是小数位)移动到更适合计算机的数字系统。在base-2中使用32位或64位整数会快得多。你可以为每次计算做更多的工作,也可以去掉所有的模数计算。
除此之外,你可以用更好的东西取代(普通的)乘法算法。如果您的数字开始变得非常大,您可以通过迁移到不同的复杂区域来获得巨大的加速。您的算法具有复杂度O(n * m),其中n和m是两个因子的位数。
快速傅里叶变换可用于在O(n log n)中更快地进行大量乘法。值得一提的是Number Theoretic Transform,它更适合这项任务。
在大整数算术的主题中有很多东西需要学习和探索。如果你只是想增加数字并且不关心它是如何完成的,我建议只使用经过测试的快速bignum库。
答案 1 :(得分:2)
是的 - 这是一个逐位操作。
你有更明智的选择,可以更快地完成任务。一个是二元运算,你将其中一个数字视为两个幂的和,结果也是你得到的部分结果的总和乘以二的幂。
例如,让我们做17 x 11(我相信它应该给我181个。)
因此,让我们将17视为2的幂。它是2 0 + 2 4 (即1 + 16)。因此我们可以取11 * 1 + 11 * 16.我们可以用移位进行这些乘法中的每一个,所以它是11 <&lt; 0 + 11&lt;&lt; 4。
另一种看待事物的方式(导致一种不同的做事方式)对大数字很有用。为了论证,我们假设您只能进行4位操作。在这种情况下,您可以将4位数中的每个数字考虑在内,并使用乘法的分配属性来得到结果 - 也就是说,我们取每个大数,并将其分解为数字之和,每个数字都是表示构成整数的位的“切片”。例如,考虑像0x1234 * 0x4321这样的东西(为了简单起见),我们假设我们将它们与一个可以乘以两个8位操作数的CPU相乘以产生一个16位的结果。因此,我们将每个分解为8位切片:
(0x1200 + 0x34) * (0x4300 + 0x21)
然后我们可以使用分配属性:
0x1200 * 0x4300 + 0x1200 * 0x21 + 0x34 * 0x4300 + 0x34 * 0x21
每个(显然足够)只有8个有效位,因此我们可以在8位CPU上执行每个操作。那么你基本上只需要取4个中间结果并将它们全部加在一起。任何合理的CPU都有一个进位和一个可以用来处理这种多精度操作的加载进位指令。
虽然我在这里用8位操作显示它,但我认为这很明显如何扩展到(例如)32位或64位CPU上的256位操作数。