首先说一下霍纳法则,这对于多次幂来说,减少乘法是很重要的,因为相比加法,乘法的执行效率更低
我们先看一下这样一个多项式
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的二进制形式,所以他们的有效性被削弱了,但在某种场合下,他们还是一种很有效的算法的