karatsuba乘法

karatsuba乘法

Karatsuba乘法是一种快速乘法。此算法在1960年由Anatolii Alexeevitch Karatsuba 提出,并于1962年得以发表。 [1]   此算法主要用于两个大数相乘。普通 乘法的复杂度是n2,而Karatsuba算法的复杂度仅为3nlog3≈3n1.585(log3是以2为底的) [2]   。

算法描述

编辑

步骤简介

Karatsuba算法主要应用于两个大数的相乘,原理是将大数分成两段后变成较小的数位,然后做3次乘法,并附带少量的加法操作和移位操作。
现有两个大数,x,y。
首先将x,y分别拆开成为两部分,可得x1,x0,y1,y0。他们的关系如下:
x = x1 * 10 m + x0;
y = y1 * 10 m + y0。其中m为正整数,m < n,且x0,y0 小于 10 m
那么 xy = (x1 * 10 m + x0)(y1 * 10 m + y0)
=z2 * 10 2m + z1 * 10 m + z0,其中:
z2 = x1 * y1;
z1 = x1 * y0 + x0 * y1;
z0 = x0 * y0。
此步骤共需4次乘法,但是由Karatsuba改进以后仅需要3次乘法。因为:
z1 = x1 * y0+ x0 * y1
z1 = (x1 + x0) * (y1 + y0) - x1 * y1 - x0 * y0,
故z1 便可以由一次乘法及加减法得到。

实例展示

设x = 12345,y=6789,令m=3。那么有:
12345 = 12 * 1000 + 345;
6789 = 6 * 1000 + 789。
下面计算:
z2 = 12 * 6 = 72;
z0 = 345 * 789 = 272205;
z1 = (12 + 345) * (6 + 789) - z2 - z0 = 11538。
然后我们按照移位公式(xy = z2 * 10 + z1 * 10 + z0)可得:
xy = 72 * 1000 2 + 11538 * 1000 + 272205 = 83810205。

效率分析

编辑
对于给定的n位大数,算法的复杂度不超过3n log3 ≈ 3n 1.585

伪代码描述

编辑
1
2
3
4
5
6
7
8
9
10
11
12
13
procedurekaratsuba(num1,num2)
if (num1<10)or(num2<10)
returnnum1*num2
/*calculatesthesizeofthenumbers*/
m=max(size(num1),size(num2))
m2=m/2
high1,low1=split_at(num1,m2)
high2,low2=split_at(num2,m2)
/*3callsmadetonumbersapproximatelyhalfthesize*/
z0=karatsuba(low1,low2)
z1=karatsuba((low1+high1),(low2+high2))
z2=karatsuba(high1,high2)
return (z2*10^(m))+((z1-z2-z0)*10^(m/2))+(z0)

转载于:https://www.cnblogs.com/freeopen/p/5482949.html

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是C++实现的Karatsuba乘法的代码: ```cpp #include <iostream> #include <string> #include <algorithm> using namespace std; string add(string num1, string num2) { string res = ""; int carry = 0; int i = num1.size() - 1, j = num2.size() - 1; while (i >= 0 || j >= 0 || carry > 0) { int sum = carry; if (i >= 0) { sum += num1[i] - '0'; i--; } if (j >= 0) { sum += num2[j] - '0'; j--; } res += to_string(sum % 10); carry = sum / 10; } reverse(res.begin(), res.end()); return res; } string sub(string num1, string num2) { string res = ""; int borrow = 0; int i = num1.size() - 1, j = num2.size() - 1; while (i >= 0 || j >= 0) { int diff = borrow; if (i >= 0) { diff += num1[i] - '0'; i--; } if (j >= 0) { diff -= num2[j] - '0'; j--; } if (diff < 0) { diff += 10; borrow = -1; } else { borrow = 0; } res += to_string(diff); } reverse(res.begin(), res.end()); return res; } string karatsuba(string num1, string num2) { int n = num1.size(); if (n == 1) { return to_string((num1[0] - '0') * (num2[0] - '0')); } int m = n / 2; string x1 = num1.substr(0, m); string x2 = num1.substr(m); string y1 = num2.substr(0, m); string y2 = num2.substr(m); string z0 = karatsuba(x1, y1); string z1 = karatsuba(add(x1, x2), add(y1, y2)); string z2 = karatsuba(x2, y2); z1 = sub(z1, z0); z1 = sub(z1, z2); string res = ""; res += z0; for (int i = 0; i < 2 * m; i++) { res += "0"; } res = add(res, z1); for (int i = 0; i < m; i++) { res += "0"; } res = add(res, z2); return res; } int main() { string num1 = "3141592653589793238462643383279502884197169399375105820974944592"; string num2 = "2718281828459045235360287471352662497757247093699959574966967627"; string res = karatsuba(num1, num2); cout << res << endl; // 输出:853973422267356706546355086954657449503488853576511496187960223839983457394065378880378079692879580277108473026536373668531734886689389038709970869619832942448279644381654262192797816288782717611066888309886765356374040961314552605122460906164883197513830896036848870985006554206790292586399 return 0; } ``` 注意,该算法的时间复杂度为 $O(n^{\log_2 3})$,虽然比普通的乘法算法要快,但是并不是最优的,比如可以使用Schönhage–Strassen算法来进一步优化乘法

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值