分治法的經典問題——大整數相乘


分治法的經典問題——大整數相乘

分治法的原理

       分治算法的基本思想是將一個規模為N的問題分解為K個規模較小的子問題,這些子問題相互獨立且與原問題性質相同。求出子問題的解,就可得到原問題的解。即一種分目標完成程序算法,簡單問題可用二分法完成。(來自度娘的搬運工)

       簡單的說,分治就是分而治之,把一個問題拆分成幾個小問題,最后再匯總解決的辦法。

有兩點需要記住:

(1) 分治法基本思想是將一個規模為n的問題分解為k個規模較小的子問題,這些子問題相互獨立且與原問題相同。

(2)遞歸的解這些子問題,然后將各子問題的解合並得到原問題的解。

分治法的重點是分析問題是否可以划分為規模較小的子問題,難點是如何划分以及划分之后如何將各個子問題的解合並成最終的解。這一般需要用到數學知識或者其他理論。

下面我們用圖來說明:

 

 

通過大整數相乘問題來了解分治法(理想狀態下)

       這里我們假設有兩個大整數X、Y,分別設X=1234、Y=5678。現在要求X*Y的乘積,小學的算法就是把X與Y中的每一項去乘,但是這樣的乘法所需的時間復雜度為,效率比較低下。那我們可以采用分治的算法,將X、Y分別拆分為A與B、C與D,如下圖:

 

 

 

注:我們這里取的大整數X、Y是在理想狀態下,即X與Y的位數一致,且

 

 

算法分析

  1. 首先將X和Y分成A,B,C,D
  2. 此時將X和Y的乘積轉化為(1)式,把問題轉化為求解因式分解的值

在(1)式中,我們一共需要進行4次n/2的乘法(AC2次,AD、BC各一次)和3次加法,因而該算法的時間復雜度為:

 

通過master定理可以求得,跟小學算法的時間復雜度沒有區別。

但是我們再來看看,我們是否可以用加法來換取乘法?因為多一個加法操作,也是常數項,對時間復雜度沒有影響,如果減少一個乘法則不同。

(1)式化為:

 (2)

現在的時間復雜度為:,通過master定理求得,

理想狀態下代碼實現(部分):

c#:

static void Main(string[] args)
        {
            //SameNumber();
            //UnSameNumber();
            UnSameNumber2();
        }

        static int SIGN(long A)
        {
            return A > 0 ? 1 : -1;
        }

        #region 兩整數位數相同
        private static void SameNumber()
        {
            Console.Write("請輸入兩個大整數:\nX=");
            long X = Convert.ToInt64(Console.ReadLine());
            Console.Write("Y=");
            long Y = Convert.ToInt64(Console.ReadLine());
            Console.Write("請輸入兩個大整數的長度:n=");
            int n = Convert.ToInt32(Console.ReadLine());

            long sum = CalculateSame(X, Y, n);

            Console.WriteLine("普通乘法 X*Y={0}*{1}={2}\n", X, Y, X * Y);
            Console.WriteLine("分治乘法 X*Y={0}*{1}={2}\n", X, Y, sum);
        }

        static long CalculateSame(long X, long Y, int n)
        {
            int sign = SIGN(X) * SIGN(Y);

            X = Math.Abs(X);
            Y = Math.Abs(Y);
            if (X == 0 || Y == 0)
                return 0;
            else if (n == 1)
                return sign * X * Y;
            else
            {
                long A = (long)(X / Math.Pow(10, n / 2));
                long B = (long)(X % Math.Pow(10, n / 2));
                long C = (long)(Y / Math.Pow(10, n / 2));
                long D = (long)(Y % Math.Pow(10, n / 2));

                long AC = CalculateSame(A, C, n / 2);
                long BD = CalculateSame(B, D, n / 2);
                long ABCD = CalculateSame((A - B), (D - C), n / 2) + AC + BD;

                //Console.WriteLine("A={0} B={1} C={2} D={3}\n", A, B, C, D);

                return (long)(sign * (AC * Math.Pow(10, n) + ABCD * Math.Pow(10, n / 2) + BD));
            }
        }
        #endregion

 

 

大整數相乘算法非理想狀態下

       這里我們還是假設有兩個大整數X、Y,分別設X=123、Y=45678。現在要求X*Y的乘積,乘法所需的時間復雜度為。我們采用分治的算法,將X、Y分別拆分為A與B、C與D,如下圖:

 

        (3)

在(3)式中,我們一共需要進行2次xn0的乘法(AC、AD各一次)、2次yn0的乘法(AC、BC各一次)和3次加法,因而該算法的時間復雜度為:

 

現在我們用加法來換取乘法並計算其時間復雜度。

(3)式化為:

(4)

 

現在的時間復雜度為:

 

由於,所以(4)式的時間復雜度小於(3)式的時間復雜度。

非理想狀態下代碼實現(部分):

c#:

 #region 兩整數位數不相同
        private static void UnSameNumber2()
        {
            Console.Write("請輸入兩個大整數:\nX=");
            long X = Convert.ToInt64(Console.ReadLine());
            Console.Write("Y=");
            long Y = Convert.ToInt64(Console.ReadLine());
            Console.Write("請輸入X的長度:xn=");
            int xn = Convert.ToInt32(Console.ReadLine());
            Console.Write("請輸入Y的長度:yn=");
            int yn = Convert.ToInt32(Console.ReadLine());

            long sum = CalculateUnSame2(X, Y, xn, yn);

            Console.WriteLine("\n普通乘法 X*Y={0}*{1}={2}", X, Y, X * Y);
            Console.WriteLine("分治乘法 X*Y={0}*{1}={2}\n", X, Y, sum);
        }

        static long CalculateUnSame2(long X, long Y, int xn, int yn)
        {
            if (X == 0 || Y == 0)
                return 0;
            else if ((xn == 1 && yn == 1) || xn == 1 || yn == 1)
                return X * Y;
            else
            {
                int xn0 = xn / 2, yn0 = yn / 2;
                int xn1 = xn - xn0, yn1 = yn - yn0;

                long A = (long)(X / Math.Pow(10, xn0));
                long B = (long)(X % Math.Pow(10, xn0));
                long C = (long)(Y / Math.Pow(10, yn0));
                long D = (long)(Y % Math.Pow(10, yn0));

                //Console.WriteLine("A={0}*10^{1} B={2}*10^{3} C={4}*10^{5} D={6}*10^{7}\n", A, xn1, B, xn0, C, yn1, D, yn0);

                long AC = CalculateUnSame2(A, C, xn1, yn1);
                long BD = CalculateUnSame2(B, D, xn0, yn0);
                long ABCD = CalculateUnSame2((long)(A * Math.Pow(10, xn0) - B), (long)(D - C * Math.Pow(10, yn0)), xn1, yn1);

                return (long)(2 * AC * Math.Pow(10, (xn0 + yn0)) + ABCD + 2 * BD);
            }
        }
        #endregion

  

 

 

理想狀態下與非理想狀態下代碼實現(完整):

c語言:

#include<stdio.h>
#include<stdlib.h>
#include<math.h>

void SameNumber();
void UnSameNumber();
int SIGN(long A);
long CalculateSame(long X, long Y, int n);
long CalculateUnSame(long X, long Y, int xn, int yn);

int main()
{
	SameNumber();
	UnSameNumber();
	return (0);
}

int SIGN(long A)
{
	return A > 0 ? 1 : -1;
}

void SameNumber()
{
	long X=0,Y = 0;
	int n=0;
	printf("理想狀態下用法!");
	printf("請輸入兩個大整數:\nX=");
	scanf("%d",&X);
	printf("Y=");
	scanf("%d",&Y);
	printf("請輸入兩個大整數的長度:n=");
	scanf("%d",&n);

	long sum = CalculateSame(X, Y, n);

	printf("普通乘法 X*Y=%d*%d=%d\n",X,Y,X*Y);
	printf("分治乘法 X*Y=%d*%d=%d\n",X,Y,sum);
}

long CalculateSame(long X, long Y, int n)
{
	int sign = SIGN(X) * SIGN(Y);

	X = labs(X);
	Y = labs(Y);
	if (X == 0 || Y == 0)
		return 0;
	else if (n == 1)
		return sign * X * Y;
	else
	{
		long A = (long)(X / pow(10, n / 2));
		long B = (X % (long)pow(10, n / 2));
		long C = (long)(Y / pow(10, n / 2));
		long D = (Y % (long)pow(10, n / 2));

		long AC = CalculateSame(A, C, n / 2);
		long BD = CalculateSame(B, D, n / 2);
		long ABCD = CalculateSame((A - B), (D - C), n / 2) + AC + BD;
		
		//cout<<"A="<<A<<" B="<<B<<" C="<<C<<" D="<<D<<endl;

		return (long)(sign * (AC * pow(10, n) + ABCD * pow(10, n / 2) + BD));
	}
}

void UnSameNumber()
{
	long X=0,Y = 0;
	int xn=0,yn=0;
	printf("非理想狀態下用法!");
	printf("請輸入兩個大整數:\nX=");
	scanf("%d",&X);
	printf("Y=");
	scanf("%d",&Y);
	printf("請輸入X的長度:xn=");
	scanf("%d",&xn);
	printf("請輸入Y的長度:xn=");
	scanf("%d",&yn);

	long sum = CalculateUnSame(X, Y, xn,yn);

	printf("普通乘法 X*Y=%d*%d=%d\n",X,Y,X*Y);
	printf("分治乘法 X*Y=%d*%d=%d\n",X,Y,sum);
}

long CalculateUnSame(long X, long Y, int xn, int yn)
{
	if (X == 0 || Y == 0)
		return 0;
	else if ((xn == 1 && yn == 1) || xn == 1 || yn == 1)
		return X * Y;
	else
	{
		int xn0 = xn / 2, yn0 = yn / 2;
		int xn1 = xn - xn0, yn1 = yn - yn0;

		long A = (long)(X / pow(10, xn0));
		long B = (long)(X % (long)pow(10, xn0));
		long C = (long)(Y / pow(10, yn0));
		long D = (long)(Y % (long)pow(10, yn0));

		long AC = CalculateUnSame(A, C, xn1, yn1);
		long BD = CalculateUnSame(B, D, xn0, yn0);
		long ABCD = CalculateUnSame((long)(A * pow(10, xn0) - B), (long)(D - C * pow(10, yn0)), xn1, yn1);

		return (long)(2 * AC * pow(10, (xn0 + yn0)) + ABCD + 2 * BD);
	}
}

  

c++語言:

#include <iostream>
#include <string> 
#include <math.h>
int count=0;
using namespace std;
void SameNumber();
void UnSameNumber();
int SIGN(long A);
long CalculateSame(long X, long Y, int n);
long CalculateUnSame(long X, long Y, int xn, int yn);

int main()
{
	SameNumber();
	UnSameNumber();
	return (0);
}

int SIGN(long A)
{
	return A > 0 ? 1 : -1;
}

void SameNumber()
{
	cout<<"理想狀態用法!"<<endl;;
	cout<<"請輸入兩個大整數:\nX=";
	long X = 0;
	cin>>X;
	cout<<"Y=";
	long Y = 0;
	cin>>Y;
	cout<<"請輸入兩個大整數的長度:n=";
	int n = 0;
	cin>>n;

	long sum = CalculateSame(X, Y, n);

	cout<<"普通乘法 X*Y="<<X<<"*"<<Y<<"="<<X * Y<<endl;
	cout<<"分治乘法 X*Y="<<X<<"*"<<Y<<"="<<sum<<endl;
}

long CalculateSame(long X, long Y, int n)
{
	int sign = SIGN(X) * SIGN(Y);

	X = abs(X);
	Y = abs(Y);
	if (X == 0 || Y == 0)
		return 0;
	else if (n == 1)
		return sign * X * Y;
	else
	{
		long A = (long)(X / pow(10, n / 2));
		long B = (X % (long)pow(10, n / 2));
		long C = (long)(Y / pow(10, n / 2));
		long D = (Y % (long)pow(10, n / 2));

		long AC = CalculateSame(A, C, n / 2);
		long BD = CalculateSame(B, D, n / 2);
		long ABCD = CalculateSame((A - B), (D - C), n / 2) + AC + BD;
		
		cout<<"A="<<A<<" B="<<B<<" C="<<C<<" D="<<D<<endl;

		return (long)(sign * (AC * pow(10, n) + ABCD * pow(10, n / 2) + BD));
	}
}

void UnSameNumber()
{
	cout<<"\n非理想狀態用法!"<<endl;;
	cout<<"請輸入兩個大整數:\nX=";
	long X = 0;
	cin>>X;
	cout<<"Y=";
	long Y = 0;
	cin>>Y;
	cout<<"請輸入兩個大整數的長度:xn=";
	int xn = 0;
	cin>>xn;
	cout<<"請輸入兩個大整數的長度:yn=";
	int yn = 0;
	cin>>yn;

	long sum = CalculateUnSame(X, Y, xn,yn);

	cout<<"普通乘法 X*Y="<<X<<"*"<<Y<<"="<<X * Y<<endl;
	cout<<"分治乘法 X*Y="<<X<<"*"<<Y<<"="<<sum<<endl;
}

long CalculateUnSame(long X, long Y, int xn, int yn)
{
	if (X == 0 || Y == 0)
		return 0;
	else if ((xn == 1 && yn == 1) || xn == 1 || yn == 1)
		return X * Y;
	else
	{
		int xn0 = xn / 2, yn0 = yn / 2;
		int xn1 = xn - xn0, yn1 = yn - yn0;

		long A = (long)(X / pow(10, xn0));
		long B = (long)(X % (long)pow(10, xn0));
		long C = (long)(Y / pow(10, yn0));
		long D = (long)(Y % (long)pow(10, yn0));

		long AC = CalculateUnSame(A, C, xn1, yn1);
		long BD = CalculateUnSame(B, D, xn0, yn0);
		long ABCD = CalculateUnSame((long)(A * pow(10, xn0) - B), (long)(D - C * pow(10, yn0)), xn1, yn1);

		return (long)(2 * AC * pow(10, (xn0 + yn0)) + ABCD + 2 * BD);
	}
}

  

c#語言:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace BigInteger
{
	class Program
	{
		static void Main(string[] args)
		{
          	SameNumber();
			UnSameNumber();
		}

		static int SIGN(long A)
		{
			return A > 0 ? 1 : -1;
		}

		#region 兩整數位數相同
		private static void SameNumber()
		{
			Console.Write("請輸入兩個大整數:\nX=");
			long X = Convert.ToInt64(Console.ReadLine());
			Console.Write("Y=");
			long Y = Convert.ToInt64(Console.ReadLine());
			Console.Write("請輸入兩個大整數的長度:n=");
			int n = Convert.ToInt32(Console.ReadLine());

			long sum = CalculateSame(X, Y, n);

			Console.WriteLine("普通乘法 X*Y={0}*{1}={2}\n", X, Y, X * Y);
			Console.WriteLine("分治乘法 X*Y={0}*{1}={2}\n", X, Y, sum);
		}

		static long CalculateSame(long X, long Y, int n)
		{
			int sign = SIGN(X) * SIGN(Y);

			X = Math.Abs(X);
			Y = Math.Abs(Y);
			if (X == 0 || Y == 0)
				return 0;
			else if (n == 1)
				return sign * X * Y;
			else
			{
				long A = (long)(X / Math.Pow(10, n / 2));
				long B = (long)(X % Math.Pow(10, n / 2));
				long C = (long)(Y / Math.Pow(10, n / 2));
				long D = (long)(Y % Math.Pow(10, n / 2));

				long AC = CalculateSame(A, C, n / 2);
				long BD = CalculateSame(B, D, n / 2);
				long ABCD = CalculateSame((A - B), (D - C), n / 2) + AC + BD;

				return (long)(sign * (AC * Math.Pow(10, n) + ABCD * Math.Pow(10, n / 2) + BD));
			}
		}
		#endregion

		#region 兩整數位數不相同
		private static void UnSameNumber()
		{
			Console.Write("請輸入兩個大整數:\nX=");
			long X = Convert.ToInt64(Console.ReadLine());
			Console.Write("Y=");
			long Y = Convert.ToInt64(Console.ReadLine());
			Console.Write("請輸入X的長度:xn=");
			int xn = Convert.ToInt32(Console.ReadLine());
			Console.Write("請輸入Y的長度:yn=");
			int yn = Convert.ToInt32(Console.ReadLine());

			long sum = CalculateUnSame(X, Y, xn, yn);

			Console.WriteLine("\n普通乘法 X*Y={0}*{1}={2}", X, Y, X * Y);
			Console.WriteLine("分治乘法 X*Y={0}*{1}={2}\n", X, Y, sum);
		}

		static long CalculateUnSame(long X, long Y, int xn, int yn)
		{
			if (X == 0 || Y == 0)
				return 0;
			else if ((xn == 1 && yn == 1) || xn == 1 || yn == 1)
				return X * Y;
			else
			{
				int xn0 = xn / 2, yn0 = yn / 2;
				int xn1 = xn - xn0, yn1 = yn - yn0;

				long A = (long)(X / Math.Pow(10, xn0));
				long B = (long)(X % Math.Pow(10, xn0));
				long C = (long)(Y / Math.Pow(10, yn0));
				long D = (long)(Y % Math.Pow(10, yn0));

				long AC = CalculateUnSame(A, C, xn1, yn1);
				long BD = CalculateUnSame(B, D, xn0, yn0);
				long ABCD = CalculateUnSame((long)(A * Math.Pow(10, xn0) - B), (long)(D - C * Math.Pow(10, yn0)), xn1, yn1);

				return (long)(2 * AC * Math.Pow(10, (xn0 + yn0)) + ABCD + 2 * BD);
			}
		}
		#endregion
    }
}

  

Java語言:

import java.util.ArrayList; 
import java.util.Date; 
import java.util.List;
import java.io.*;
import java.util.Scanner;
import java.util.Collections;
import java.util.Comparator;
import java.util.Random;

public class Program
{
	public static Scanner sc = new Scanner(System.in);
	public static int count=0;
	public static void main(String[] args)
	{
		SameNumber();
		UnSameNumber();
	}

	public static int SIGN(long A)
	{
		return A > 0 ? 1 : -1;
	}

	//兩整數位數相同
	private static void SameNumber()
	{
		System.out.print("請輸入兩個大整數:\nX=");
		long X = sc.nextLong();
		System.out.print("Y=");
		long Y = sc.nextLong();
		System.out.print("請輸入兩個大整數的長度:n=");
		int n = sc.nextInt();

		long sum = CalculateSame(X, Y, n);

		System.out.println("普通乘法 X*Y="+X+"*"+Y+"="+X*Y+"\n");
		System.out.println("分治乘法 X*Y="+X+"*"+Y+"="+sum+"\n");
	}

	public static long CalculateSame(long X, long Y, int n)
	{
		int sign = SIGN(X) * SIGN(Y);

		X = Math.abs(X);
		Y = Math.abs(Y);
		if (X == 0 || Y == 0)
			return 0;
		else if (n == 1)
			return sign * X * Y;
		else
		{
			long A = (long)(X / Math.pow(10, n / 2));
			long B = (long)(X % Math.pow(10, n / 2));
			long C = (long)(Y / Math.pow(10, n / 2));
			long D = (long)(Y % Math.pow(10, n / 2));

			long AC = CalculateSame(A, C, n / 2);
			long BD = CalculateSame(B, D, n / 2);
			long ABCD = CalculateSame((A - B), (D - C), n / 2) + AC + BD;

			return (long)(sign * (AC * Math.pow(10, n) + ABCD * Math.pow(10, n / 2) + BD));
		}
	}

//兩整數位數不同
	private static void UnSameNumber()
	{
		System.out.print("請輸入兩個大整數:\nX=");
		long X = sc.nextLong();
		System.out.print("Y=");
		long Y = sc.nextLong();
		System.out.print("請輸入X的長度:xn=");
		int xn = sc.nextInt();
		System.out.print("請輸入Y的長度:yn=");
		int yn = sc.nextInt();

		long sum = CalculateUnSame(X, Y, xn, yn);

		System.out.println("普通乘法 X*Y="+X+"*"+Y+"="+X*Y+"\n");
		System.out.println("分治乘法 X*Y="+X+"*"+Y+"="+sum+"\n");
	}

	public static long CalculateUnSame(long X, long Y, int xn, int yn)
	{
		if (X == 0 || Y == 0)
			return 0;
		else if ((xn == 1 && yn == 1) || xn == 1 || yn == 1)
			return X * Y;
		else
		{
			int xn0 = xn / 2, yn0 = yn / 2;
			int xn1 = xn - xn0, yn1 = yn - yn0;

			long A = (long)(X / Math.pow(10, xn0));
			long B = (long)(X % Math.pow(10, xn0));
			long C = (long)(Y / Math.pow(10, yn0));
			long D = (long)(Y % Math.pow(10, yn0));

			long AC = CalculateUnSame(A, C, xn1, yn1);
			long BD = CalculateUnSame(B, D, xn0, yn0);
			long ABCD = CalculateUnSame((long)(A * Math.pow(10, xn0) - B), (long)(D - C * Math.pow(10, yn0)), xn1, yn1);

			return (long)(2 * AC * Math.pow(10, (xn0 + yn0)) + ABCD + 2 * BD);
		}
	}
}

  

JavaScript語言:

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<script>
function SIGN(A)
{
	return A > 0 ? 1 : -1;
}

function SameNumber()
{
	var str = "";
	var X = document.getElementById('SX').value;
	var Y = document.getElementById('SY').value;
	var n = document.getElementById('Sn').value;

	var sum = CalculateSame(X, Y, n);

	str += "普通乘法 X*Y="+X+"*"+Y+"="+X * Y+"<br/>";
	str += "分治乘法 X*Y="+X+"*"+Y+"="+sum;
	document.getElementById('oldcontent').innerHTML = str;
}

function CalculateSame(X, Y, n)
{
	var sign = SIGN(X) * SIGN(Y);

	X = Math.abs(X);
	Y = Math.abs(Y);
	if (X == 0 || Y == 0)
		return 0;
	else if (n == 1)
		return sign * X * Y;
	else
	{
		var A = parseInt(X / Math.pow(10, n / 2));
		var B = parseInt(X % Math.pow(10, n / 2));
		var C = parseInt(Y / Math.pow(10, n / 2));
		var D = parseInt(Y % Math.pow(10, n / 2));

		var AC = CalculateSame(A, C, n / 2);
		var BD = CalculateSame(B, D, n / 2);
		var ABCD = CalculateSame((A - B), (D - C), n / 2) + AC + BD;

		return (sign * (AC * Math.pow(10, n) + ABCD * Math.pow(10, n / 2) + BD));
	}
}

function UnSameNumber()
{
	var str = "";
	var X = document.getElementById('KX').value;
	var Y = document.getElementById('KY').value;
	var xn = document.getElementById('xn').value;
	var yn = document.getElementById('yn').value;

	var sum = CalculateUnSame(X, Y, xn, yn);

	str += "普通乘法 X*Y="+X+"*"+Y+"="+X * Y+"<br/>";
	str += "分治乘法 X*Y="+X+"*"+Y+"="+sum;
	document.getElementById('newcontent').innerHTML = str;

}

function CalculateUnSame(X,Y,xn,yn)
{
	if (X == 0 || Y == 0)
		return 0;
	else if ((xn == 1 && yn == 1) || xn == 1 || yn == 1)
		return X * Y;
	else
	{
		var xn0 = parseInt(xn / 2), yn0 = parseInt(yn / 2);
		var xn1 = xn - xn0, yn1 = yn - yn0;

		var A = parseInt(X / Math.pow(10, xn0));
		var B = parseInt(X % Math.pow(10, xn0));
		var C = parseInt(Y / Math.pow(10, yn0));
		var D = parseInt(Y % Math.pow(10, yn0));

		var AC = CalculateUnSame(A, C, xn1, yn1);
		var BD = CalculateUnSame(B, D, xn0, yn0);
		var ABCD = CalculateUnSame((A * Math.pow(10, xn0) - B), (D - C * Math.pow(10, yn0)), xn1, yn1);

		return (2 * AC * Math.pow(10, (xn0 + yn0)) + ABCD + 2 * BD);
	}
}
</script>
<body>
<div>請輸入兩個大整數:X=<input id="SX"/> Y=<input id="SY"/> 請輸入兩個大整數的長度:n=<input id="Sn"/>
<input type="button" onclick="SameNumber()" value="計算"/></div>
<div id="oldcontent"></div>
<div>請輸入兩個大整數:X=<input id="KX"/> Y=<input id="KY"/> 請輸入X的長度:xn=<input id="xn"/>請輸入Y的長度:yn=<input id="yn"/>
<input type="button" onclick="UnSameNumber()" value="計算"/></div>
<div id="newcontent"></div>
</body>
</html>

  

PHP語言:

<?php
error_reporting(E_ALL ^ E_NOTICE);
SameNumber();
UnSameNumber();

function SameNumber()
{
	fwrite(STDOUT, "理想狀態算法!\n請輸入兩個大整數:\nX=");
	$X = trim(fgets(STDIN));
	fwrite(STDOUT, "Y=");
	$Y = trim(fgets(STDIN));
	fwrite(STDOUT, "請輸入兩個大整數的長度:n=");
	$n = trim(fgets(STDIN));

	$sum = CalculateSame($X, $Y, $n);

	echo "普通乘法 X*Y=".$X."*".$Y."=".$X*$Y."\n";
	echo "分治乘法 X*Y=".$X."*".$Y."=".$sum."\n";
}

function SIGN($A)
{
	return $A > 0 ? 1 : -1;
}

function CalculateSame($X,$Y,$n)
{
	$sign = SIGN($X) * SIGN($Y);

	$X = abs($X);
	$Y = abs($Y);
	if ($X == 0 || $Y == 0)
		return 0;
	else if ($n == 1)
		return $sign * $X * $Y;
	else
	{
		$A = intval($X / pow(10, $n / 2));
		$B = intval($X % pow(10, $n / 2));
		$C = intval($Y / pow(10, $n / 2));
		$D = intval($Y % pow(10, $n / 2));

		//echo"sign=".$sign." pow=".pow(10, $n / 2)." X=".$X." Y=".$Y." A=".$A." B=".$B." C=".$C." D=".$D."\n";

		$AC = CalculateSame($A, $C, $n / 2);
		$BD = CalculateSame($B, $D, $n / 2);
		$ABCD = CalculateSame(($A - $B), ($D - $C), $n / 2) + $AC + $BD;
		
		//echo "sum=".( $AC * pow(10, $n) )." AC=".$AC." BD=".$BD." ABCD=".$ABCD."\n";

		return ($sign * ($AC * pow(10, $n) + $ABCD * pow(10, $n / 2) + $BD));
	}
}

function UnSameNumber()
{
	fwrite(STDOUT, "\n非理想狀態!\n請輸入兩個大整數:\nX=");
	$X = trim(fgets(STDIN));
	fwrite(STDOUT, "Y=");
	$Y = trim(fgets(STDIN));
	fwrite(STDOUT, "請輸入X的長度:xn=");
	$xn = trim(fgets(STDIN));
	fwrite(STDOUT, "請輸入Y的長度:yn=");
	$yn = trim(fgets(STDIN));

	$sum = CalculateUnSame($X, $Y, $xn,$yn);

	echo "普通乘法 X*Y=".$X."*".$Y."=".$X*$Y."\n";
	echo "分治乘法 X*Y=".$X."*".$Y."=".$sum."\n";
}

function CalculateUnSame($X,$Y,$xn,$yn)
{
	if ($X == 0 || $Y == 0)
		return 0;
	else if (($xn == 1 && $yn == 1) || $xn == 1 || $yn == 1)
		return $X * $Y;
	else
	{
		$xn0 = intval($xn / 2);
		$yn0 = intval($yn / 2);
		$xn1 = $xn - $xn0;
		$yn1 = $yn - $yn0;

		$A = intval($X / pow(10, $xn0));
		$B = intval($X % pow(10, $xn0));
		$C = intval($Y / pow(10, $yn0));
		$D = intval($Y % pow(10, $yn0));

		echo"X=".$X." Y=".$Y." A=".$A." B=".$B." C=".$C." D=".$D."\n";

		$AC = CalculateUnSame($A, $C, $xn1, $yn1);
		$BD = CalculateUnSame($B, $D, $xn0, $yn0);
		$ABCD = CalculateUnSame(($A * pow(10, $xn0) - $B), ($D - $C * pow(10, $yn0)), $xn1, $yn1);

		//echo "sum=".( $AC * pow(10, $n) )." AC=".$AC." BD=".$BD." ABCD=".$ABCD."\n";

		return (2 * $AC * pow(10, ($xn0 + $yn0)) + $ABCD + 2 * $BD);
	}
}
?>

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM