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