要求:
计算两个大数X,Y的乘法,要求时间小于n^2.
方法:
分治法,将两个数分解为等长的两段。
X(n)= (a*10^m + b) , Y(n) = (c *10^m + d);(其中m = n/2)
X*Y = a*c*S(2m) + b*d + (ad + bc)*S(m);
这里需要4次乘法(a*c, b*d, a*d, b*c),*S(m)不为乘法,通过位置/位移来控制。
其中ad + bc = (a +b)*(c +d) - ac -bd。
X*Y = a*c*S(2m) + b*d + ((a +b)*(c +d) - ac -bd)*S(m);
因此只需要3次乘法,若干次加法和位置拷贝操作。
O(F(n)) = O( X(n)*Y(n)) = O(3F(n/2) + n) = n^(log3)
代码
//******************************************************************************************
private static BigData praseString2BigData(String str) {
BigData result = new BigData();
result.len = str.length();
result.data = new int[result.len];
int loop = 0;
byte[] byteNum = str.getBytes();
for (int index = byteNum.length - 1; index >= 0; index--) {
result.data[loop] = byteNum[index] - '0';
loop++;
}
return result;
}
private static String praseBigData2Str(BigData bigData) {
StringBuilder builder = new StringBuilder();
for (int index = bigData.len - 1; index >= 0; index--) {
builder.append(bigData.data[index]);
}
return builder.toString();
}
public static class BigData {
public int[] data;
public int len;
public BigData(int len) {
data = new int[len];
this.len = 0;
}
public BigData() {
len = 0;
}
}
private static BigData add(BigData input1, BigData input2) {
int bigLen = Math.max(input1.len, input2.len) + 1;
BigData result = new BigData(bigLen);
int shift = 0;
int num1;
int num2;
int countNum;
for (int loop = 0; loop < bigLen; loop++) {
num1 = loop < input1.len ? input1.data[loop] : 0;
num2 = loop < input2.len ? input2.data[loop] : 0;
countNum = num1 + num2 + shift;
shift = countNum / 10;
result.data[loop] = countNum % 10;
}
result.len = result.data[bigLen - 1] == 0 ? bigLen - 1 : bigLen;
return result;
}
private static BigData shiftLeft(BigData input, int len) {
int bigLen = input.len + len;
BigData result = new BigData(bigLen);
System.arraycopy(input.data, 0, result.data, len, input.len);
result.len = bigLen;
return result;
}
private static BigData singleMultiply(final int input1, BigData input2) {
BigData result = new BigData();
result.len = input2.len + 1;
result.data = new int[result.len];
int num2;
int shift = 0;
int out;
int outLen = 0;
for (int loop = 0; loop < result.len; loop++) {
num2 = loop < input2.len ? input2.data[loop] : 0;
out = input1 * num2 + shift;
result.data[loop] = out % 10;
shift = out < 10 ? 0 : out / 10;
if (out != 0) {
outLen = loop;
}
}
result.len = outLen + 1;
return result;
}
private static void seperate(BigData input, int lowLen, BigData outputHigh, BigData outputLow) {
outputHigh.len = input.len - lowLen;
outputLow.len = lowLen;
outputHigh.data = new int[outputHigh.len];
outputLow.data = new int[outputLow.len];
System.arraycopy(input.data, 0, outputLow.data, 0, outputLow.len);
System.arraycopy(input.data, outputLow.len, outputHigh.data, 0, outputHigh.len);
return;
}
private static BigData delete(BigData input1, BigData input2) {
int bigLen = Math.max(input1.len, input2.len);
BigData result = new BigData(bigLen);
int shift = 0;
int num1;
int num2;
int countNum;
for (int loop = 0; loop < input1.len; loop++) {
num2 = loop < input2.len ? input2.data[loop] : 0;
countNum = input1.data[loop] - num2 - shift;
if (countNum < 0) {
shift = 1;
countNum = 10 + countNum;
} else {
shift = 0;
}
result.data[loop] = countNum;
if (countNum != 0) {
result.len = loop;
}
}
result.len += 1;
return result;
}
/**
*
* X = 10^s *a + b
* Y = 10^s *c + d
* X * Y = 10^(2s)ac + bd + 10^s( ad + bc)
* =10^(2s)ac + bd + 10^s( (a + b) * (c + d) - ac - bd)
* @param input1
* @param input2
* @return
*/
private static BigData multiply(BigData input1, BigData input2) {
if (input1.len == 1) {
return singleMultiply(input1.data[0], input2);
}
if (input2.len == 1) {
return singleMultiply(input2.data[0], input1);
}
int inputLowLen = Math.min(input1.len / 2, input2.len / 2);
BigData a = new BigData();
BigData b = new BigData();
BigData c = new BigData();
BigData d = new BigData();
seperate(input1, inputLowLen, a, b);
seperate(input2, inputLowLen, c, d);
BigData ac = multiply(a, c);
BigData bd = multiply(b, d);
BigData a_b = add(a, b);
BigData c_d = add(c, d);
BigData a_bc_d = multiply(a_b, c_d);
BigData thrd = delete(delete(a_bc_d, ac), bd);
BigData result = shiftLeft(ac, 2 * inputLowLen);
result = add(result, bd);
result = add(result, shiftLeft(thrd, inputLowLen));
return result;
}
public static void main(String[] arg) {
String strX = "3141592653589793238462643383279502884197169399375105820974944592";
String strY = "2718281828459045235360287471352662497757247093699959574966967627";
BigData x = praseString2BigData(strX);
BigData y = praseString2BigData(strY);
BigData result = multiply(x, y);
String aa = praseBigData2Str(result);
}