霍纳法则和二进制幂

首先说一下霍纳法则,这对于多次幂来说,减少乘法是很重要的,因为相比加法,乘法的执行效率更低


我们先看一下这样一个多项式

             p(x)  =  2*x^4 - 1*x^3 - 3*x^2 + 1*x^1 - 5

                     = x ( x ( x ( 2x - 1 ) + 3 ) + 1 ) - 5


再看一下霍纳法则执行过程:

 

系数 2 -1 3 1 -5
x=3 2 3 * 2 +(-1)= 5 3 * 5 + 3 = 18 3 * 18 + 1 = 55 3 * 55 + (-5)= 160

 


所以我们再看他的实现代码

 

/**
 * 霍纳法则
 * 
 * @author chenxuegui
 */
public class HornerRule
{
	public static void main(String[] args)
	{
		int[] a = new int[] { 2, -1, 3, 1, -5 };

		int x = 3;

		System.out.println(Horner(a, x));

	}

	/**
	 * 霍纳法则的核心
	 * 
	 * 如果 p(x) = 2*x^4 + x^3 - 3*x^2 + x -5 = x(x(x(2x-1)+3)+1)-5
	 * 
	 * 则数组  2 -1 3 1 -5 (次序幂告到低)
	 * 
	 * @param a
	 * @param x
	 * @return
	 */
	private static int Horner(int[] a, int x)
	{
		int result = a[0];

		for (int i = 1; i < a.length; i++)
		{
			result = result * x + a[i];
		}

		return result;
	}
}

 



同时霍纳法则还长生一种副产品,计算p(x) 在某点上的值x0时所产生的中间数,恰好可以作为p(x)除以x-x0的商的系数,而算法的最后结果,除了等于p(x0)以外,还等于这个除法的余数,对本例,  p(x)  =  2*x^4 - 1*x^3 - 3*x^2 + 1*x^1 - 5 除以 x - 3 的商为  p(x)  =  2*x^3 + 5*x^2 + 18*x^1 + 55,余数为160 ,这方法逼长除法方便



接下来看一下二进制幂

二进制幂他是一种霍纳法则在幂上的应用 

                  a^n = a^p(2) = a^( bi * 2 ^ i + ....+ b1 * 2 ^ 1)


二进制幂运算有两种实现,一种是从左到右,一种是从右到左

看一下计算a^13从左到右的二进制幂运行过程

 

n的二进制位 1 1 0 1
累加器 a a^2*a=a^3 (a^3)^2=a^6 (a^6)^2*a=a^13

 

 

实现代码在下面

再看一下计算a^13从左到右的二进制幂运行过程

 

1 1 0 1 n的二进制位
a^8 a^4 a^2 a 项a^2
a^5 * a^8 = a ^13 a * a^4 = a^5   a 累加器

 

 

 

/**
 * 二进制幂 其实核心还是使用霍纳法则的变形
 * 
 * @author chenxuegui
 * 
 */
public class BinaryExponentiation
{
	public static void main(String[] args)
	{
		// 计算3^13次

		System.out.println(leftRightBinaryExponentiation(3, new int[] { 1, 1,
				0, 1 }));
		
		/*System.out.println(rightLeftBinaryExponentiation(3, new int[] { 1, 1,
				0, 1 }));*/

	}

	/**
	 * 
	 * 如 a^13 = a^(1*2^3 + 1*2^2 + 0*2^1 + 1*2^0)
	 * 
	 * @param a
	 *            底数
	 * @param b
	 *            幂二进制霍纳表达式(数组顺序幂次高到底)
	 */
	private static int leftRightBinaryExponentiation(int a, int[] b)
	{
		int product = a;

		// b[0]一定为1(要么为1,要么为0),因为它是最高位系数,最高位系数只能是1
		for (int i = 1; i < b.length; i++)
		{
			product = product * product;

			if (b[i] == 1)
				product *= a;
		}

		return product;

	}

	/**
	 * 
	 * 如 a^13 = a^(1*2^3 + 1*2^2 + 0*2^1 + 1*2^0)
	 * 
	 * @param a
	 *            底数
	 * @param b
	 *            幂二进制霍纳表达式(数组顺序幂次高到底)
	 * @return
	 */
	private static int rightLeftBinaryExponentiation(int a, int[] b)
	{
		int product = 1;

		int term = a;

		for (int i = b.length-1; i >=0 ; i--)
		{
			if(b[i] == 1)product *=term;

			term *= term;
		}
		
		return product;
	}
}



 

该算法效率O(logn),但由于二进制幂算法依赖指数n的二进制形式,所以他们的有效性被削弱了,但在某种场合下,他们还是一种很有效的算法的




posted on 2014-01-07 16:15  love so much  阅读(1077)  评论(0编辑  收藏  举报

导航