是否存在将两个任意长整数精确乘法的算法?我正在使用的语言限制为64位无符号整数长度(最大整数大小为18446744073709551615)。实际上,我希望能够通过分解每个数字,使用无符号的64位整数以某种方式处理它们,然后能够将它们重新组合成一个字符串(这将解决相乘结果的问题)来实现这一点存储)。
有什么想法吗?
答案 0 :(得分:12)
大多数语言都有执行此操作的函数或库,通常称为Bignum库(GMP是一个很好的。)
如果你想自己做,我会这样做,就像人们在纸上长时间的乘法一样。为此,您可以使用包含数字的字符串,也可以使用按位运算以二进制方式处理。
示例:
45
x67
---
315
+270
----
585
或二进制:
101
x101
----
101
000
+101
------
11001
编辑:在二进制文件中进行后,我意识到使用按位运算代替包含基数为10的字符串进行编码会更简单(当然更快)。我编辑了我的二进制乘法示例来显示一个模式:对于底部数字中的每个1位,添加顶部数字,向左移位 1位次的位置到变量。最后,该变量将包含该产品。
要存储产品,您必须拥有两个64位数字,并想象其中一个是前64位,另一个是产品的第二个64位。您必须编写代码,将第二个数字的第63位添加到第一个数字的第0位。
答案 1 :(得分:4)
如果您无法使用现有的bignum库(如GMP),请查看Wikipedia's article on binary multiplication with computers。有很多好的,有效的算法。
答案 2 :(得分:3)
最简单的方法是使用教科书机制,将任意大小的数字分成每个32位的块。
给定A B C D * E F G H(每个块32位,总共128位)
你需要一个双十字宽的输出数组。
将[0..8]设置为0
你首先要做的是:H * D + out [8] => 64位结果。
将低32位存储在out [8]中,并将高32位作为进位
存储
下一步:(H * C)+ out [7] +携带
再次,在out [7]中存储低32位,使用高32位作为进位
在做了H * A + out [4] + carry之后,你需要继续循环,直到你没有进位。
然后用G,F,E重复。
对于G,你从[7]而不是[8]开始,依此类推。
最后,逐步完成并将大整数转换为数字(这需要“将一个大数字除以一个单词”例程)
答案 3 :(得分:1)
是的,你使用的数据类型实际上是一串数字(就像普通的'string'是一串字符一样)。你如何做到这一点是高度依赖语言的。例如,Java使用BigDecimal。你用的是哪种语言?
答案 4 :(得分:1)
这通常作为家庭作业分配。你在小学就读的算法会奏效。如果你需要一个真正的应用程序,可以使用一个库(其他帖子中提到了几个)。
答案 5 :(得分:0)
这是我的代码片段C.好旧的乘法方法
char *multiply(char s1[], char s2[]) {
int l1 = strlen(s1);
int l2 = strlen(s2);
int i, j, k = 0, c = 0;
char *r = (char *) malloc (l1+l2+1); // add one byte for the zero terminating string
int temp;
strrev(s1);
strrev(s2);
for (i = 0;i <l1+l2; i++) {
r[i] = 0 + '0';
}
for (i = 0; i <l1; i ++) {
c = 0; k = i;
for (j = 0; j < l2; j++) {
temp = get_int(s1[i]) * get_int(s2[j]);
temp = temp + c + get_int(r[k]);
c = temp /10;
r[k] = temp%10 + '0';
k++;
}
if (c!=0) {
r[k] = c + '0';
k++;
}
}
r[k] = '\0';
strrev(r);
return r;
}
答案 6 :(得分:0)
//Here is a JavaScript version of an Karatsuba Algorithm running with less time than the usual multiplication method
function range(start, stop, step) {
if (typeof stop == 'undefined') {
// one param defined
stop = start;
start = 0;
}
if (typeof step == 'undefined') {
step = 1;
}
if ((step > 0 && start >= stop) || (step < 0 && start <= stop)) {
return [];
}
var result = [];
for (var i = start; step > 0 ? i < stop : i > stop; i += step) {
result.push(i);
}
return result;
};
function zeroPad(numberString, zeros, left = true) {
//Return the string with zeros added to the left or right.
for (var i in range(zeros)) {
if (left)
numberString = '0' + numberString
else
numberString = numberString + '0'
}
return numberString
}
function largeMultiplication(x, y) {
x = x.toString();
y = y.toString();
if (x.length == 1 && y.length == 1)
return parseInt(x) * parseInt(y)
if (x.length < y.length)
x = zeroPad(x, y.length - x.length);
else
y = zeroPad(y, x.length - y.length);
n = x.length
j = Math.floor(n/2);
//for odd digit integers
if ( n % 2 != 0)
j += 1
var BZeroPadding = n - j
var AZeroPadding = BZeroPadding * 2
a = parseInt(x.substring(0,j));
b = parseInt(x.substring(j));
c = parseInt(y.substring(0,j));
d = parseInt(y.substring(j));
//recursively calculate
ac = largeMultiplication(a, c)
bd = largeMultiplication(b, d)
k = largeMultiplication(a + b, c + d)
A = parseInt(zeroPad(ac.toString(), AZeroPadding, false))
B = parseInt(zeroPad((k - ac - bd).toString(), BZeroPadding, false))
return A + B + bd
}
//testing the function here
example = largeMultiplication(12, 34)
console.log(example)