阶乘算法
java 阶乘最快算法

java 阶乘最快算法在计算阶乘时,最快的算法通常采用“分治法”,也被称为“快速阶乘算法”。
这个算法的基本思想是将大阶乘分解为若干个小阶乘,然后递归计算这些小阶乘,直到小阶乘不能再分解为止。
具体来说,快速阶乘算法的步骤如下:1. 定义一个辅助函数,该函数接受两个整数参数 n 和 m,返回 n 的 m 次方的阶乘。
2. 在主函数中,首先判断输入的整数是否为 0,如果是,则直接返回 1。
3. 如果输入的整数是负数,则将其转换为正数,并在结果中添加一个负号。
4. 将输入的整数转换为二进制表示,找到最右边的 1 位,记下该位对应的十进制数 k。
5. 递归调用辅助函数,计算 n 的 (k+1) 次方的阶乘。
6. 计算 n 的 k 次方的阶乘,并将结果乘以 (n-k) 的 k 次方的阶乘。
7. 将第 6 步的结果除以 k+1,得到最终的阶乘结果。
以下是使用 Java 实现的快速阶乘算法示例代码:```javapublic class Factorial {public static long factorial(int n) {if (n == 0) {return 1;} else if (n < 0) {return -1;} else {return factorial(n, 0);}}private static long factorial(int n, int k) {if (k == 32) { // 假设使用 32 位整数表示整数return 1;} else if ((n & (1 << k)) != 0) { // 判断二进制最右边的 1 位是否为 1 return n - (1 << k) + 1 == 0 ? factorial(n, k + 1) : n - (1 << k) + 1 == 1 ? factorial(n, k + 1) (n - (1 << k)) : factorial(n, k + 1) factorial(n - (1 << k), k);} else {return factorial(n, k + 1);}}public static void main(String[] args) {int n = 20;long result = factorial(n);(n + " 的阶乘为:" + result);}}```在这个示例代码中,我们首先定义了一个辅助函数 `factorial()`,该函数接受一个整数参数 `n`,返回 `n` 的阶乘。
组合数算法

组合数算法
组合数是一种在数学中表示从若干个不同的物品中取出若干个物品的方案数的数学概念。
它通常被表示为C(n,m),表示从n个不同的物品中取出m个物品的方案数。
在计算组合数时,常用的算法有以下几种:
1、阶乘法:C(n,m)=n!/(m!*(n-m)!)
2、动态规划法:通过构建一个二维数组来存储组合数,根据前面计算的组合数来计算后面的组合数。
3、递归法:通过递归的方式来计算组合数,可以使用递推公式C(n,m)=C(n-1,m-1)+C(n-1,m)来计算。
4、二项式反演:通过二项式反演公式C(n,m)=(-1)^m*C(m,n)来计算。
在选择算法时,可以根据实际情况来选择最合适的算法。
阶乘的快速计算方法

阶乘的快速计算方法阶乘是数学中一个非常重要的概念,它在组合数学、概率论等领域有着广泛的应用。
然而,当阶乘的数值非常大时,传统的计算方法往往会因为计算量太大而变得非常耗时。
为了解决这个问题,人们提出了一系列快速计算阶乘的方法。
一、基于递归的快速计算方法递归是一种非常常见的计算方法,它可以将一个大问题分解成若干个小问题,然后通过解决小问题来解决大问题。
对于阶乘来说,我们可以使用递归的方法来计算。
具体而言,我们可以将阶乘分解为两个部分:首先计算阶乘数n的一半,然后将结果平方得到n的阶乘。
这样,我们就可以通过递归的方式来计算阶乘。
二、基于迭代的快速计算方法除了递归,迭代也是一种常见的计算方法。
与递归不同,迭代是通过循环来实现计算的过程。
对于阶乘来说,我们可以使用迭代的方法来计算。
具体而言,我们可以使用一个循环来计算阶乘。
首先,我们将阶乘的初始值设为1,然后通过循环不断将当前值乘以下一个数,直到计算到n为止。
这样,我们就可以通过迭代的方式来计算阶乘。
三、基于公式的快速计算方法除了递归和迭代,还有一种基于公式的快速计算阶乘的方法。
这种方法通过使用数学公式来计算阶乘,从而减少计算的复杂度。
具体而言,我们可以使用斯特林公式来计算阶乘的近似值。
斯特林公式是一个近似计算阶乘的公式,它可以通过对数函数的性质来简化阶乘的计算。
使用斯特林公式,我们可以将阶乘的计算复杂度从O(n)降低到O(log n)。
四、基于查表的快速计算方法除了以上三种方法,还有一种基于查表的快速计算阶乘的方法。
这种方法通过预先计算并保存阶乘的结果,然后在需要计算阶乘时直接查表获取结果,从而减少计算的时间。
具体而言,我们可以使用动态规划的方法来计算并保存阶乘的结果。
首先,我们将阶乘的初始值设为1,并将其保存在一个表中。
然后,通过循环计算并保存每个数的阶乘结果,直到计算到n为止。
这样,当需要计算阶乘时,我们只需要从表中查找结果,而不需要重新计算。
总结起来,阶乘的快速计算方法有基于递归、迭代、公式和查表等多种方式。
阶乘的算法实验报告

一、实验目的1. 掌握阶乘算法的基本原理和实现方法;2. 分析不同阶乘算法的效率;3. 提高编程能力和算法优化能力。
二、实验环境1. 操作系统:Windows 102. 编程语言:Python3.83. 开发工具:PyCharm三、实验内容1. 阶乘算法实现2. 性能分析四、实验步骤1. 阶乘算法实现(1)递归法实现阶乘```pythondef factorial_recursive(n):if n == 0 or n == 1:return 1else:return n factorial_recursive(n - 1) ```(2)迭代法实现阶乘```pythondef factorial_iterative(n):result = 1for i in range(1, n + 1):result = ireturn result```2. 性能分析(1)测试数据为了测试不同阶乘算法的性能,我们选取以下测试数据:- 较小数值:n = 5- 较大数值:n = 10- 极大数值:n = 20(2)性能测试```pythonimport timedef test_factorial():n_list = [5, 10, 20]for n in n_list:start_time = time.time()factorial_recursive(n)recursive_time = time.time() - start_time start_time = time.time()factorial_iterative(n)iterative_time = time.time() - start_timeprint(f"n = {n}:")print(f"递归法耗时:{recursive_time:.6f}秒")print(f"迭代法耗时:{iterative_time:.6f}秒")print("")test_factorial()```五、实验结果与分析1. 实验结果(1)n = 5递归法耗时:0.000002秒迭代法耗时:0.000001秒(2)n = 10递归法耗时:0.000003秒迭代法耗时:0.000001秒(3)n = 20递归法耗时:0.000016秒迭代法耗时:0.000002秒2. 分析(1)从实验结果可以看出,迭代法在计算阶乘时比递归法具有更高的效率。
6种基本算法 递归

6种基本算法递归递归是一种重要的算法思想,它在计算机科学中得到广泛应用。
本文将介绍六种基本的递归算法,并对其原理和应用进行讲解。
一、递归的基本概念递归是指一个函数在其定义中调用自身的过程。
递归算法通过将一个大问题划分为一个或多个相同或相似的子问题,然后通过解决子问题来解决原始问题。
递归算法具有简洁、优雅以及可读性强的特点,但同时也需要注意递归的停止条件,以避免无限递归的发生。
二、阶乘算法阶乘算法是递归算法中最经典的例子之一。
它的定义如下:```n! = n * (n-1) * (n-2) * ... * 1```其中,n为一个非负整数。
阶乘算法可以通过递归的方式实现,即:```fact(n) = n * fact(n-1)```其中,停止条件为`n=0`时,返回1。
三、斐波那契数列算法斐波那契数列是一个无限序列,其定义如下:```F(0) = 0F(1) = 1F(n) = F(n-1) + F(n-2) (n>1)```斐波那契数列算法可以通过递归的方式实现,即:```fib(n) = fib(n-1) + fib(n-2)```其中,停止条件为`n=0`或`n=1`时,返回相应的值。
四、二分查找算法二分查找算法是一种高效的查找算法,它的基本原理是将已排序的数组分成两部分,然后判断目标值在哪一部分,并继续在该部分中进行查找,直到找到目标值或者查找范围为空。
二分查找算法可以通过递归的方式实现,即:```binarySearch(arr, target, start, end) = binarySearch(arr, target, start, mid-1) (target < arr[mid])= binarySearch(arr, target, mid+1, end) (target > arr[mid])= mid (target = arr[mid])```其中,`arr`为已排序的数组,`target`为目标值,`start`和`end`为查找范围的起始和结束位置。
递归算法的阶乘

递归算法的阶乘
阶乘是指一个正整数的所有小于或等于该数的正整数相乘所得的积。
例如,5的阶乘为5*4*3*2*1=120。
递归算法是一种自己调用自己的算法。
在计算阶乘时,可以使用递归算法来简化计算。
我们以计算5的阶乘为例,可以将其表示为5!=5*4*3*2*1。
但是,我们可以将其转换为5!=5*4!,其中4!表示4的阶乘。
同样,4!=4*3!,3!=3*2!,2!=2*1!,1!=1。
因此,我们可以使用递归算法来计算阶乘。
具体步骤如下:
1. 定义一个递归函数factorial(n),其中n表示要计算阶乘的数。
2. 在函数中,当n等于1时,返回1;否则,返回
n*factorial(n-1)。
3. 调用函数factorial(5)来计算5的阶乘,得到答案120。
递归算法虽然简化了计算过程,但是在实际应用中也需要注意递归深度的问题,特别是在调用次数较多的情况下,容易发生栈溢出等问题。
因此,在使用递归算法时需要谨慎使用。
- 1 -。
递归算法算阶乘

递归算法算阶乘递归算法算阶乘阶乘是数学中常见的概念,表示一个正整数n与小于等于它的所有正整数的乘积,通常用n!表示。
例如,5! = 5 × 4 × 3 × 2 × 1 = 120。
在计算机科学中,递归算法是一种常见的解决问题的方法,递归算法可以用来计算阶乘。
递归算法是一种自我调用的算法,它将问题分解成更小的子问题,直到问题变得足够简单,可以直接求解。
递归算法通常包括两个部分:基本情况和递归情况。
基本情况是指问题已经足够简单,可以直接求解的情况。
递归情况是指问题还需要继续分解成更小的子问题,直到达到基本情况。
计算阶乘的递归算法可以描述如下:1. 如果n等于0或1,返回1。
2. 否则,返回n乘以(n-1)的阶乘。
这个算法的基本情况是n等于0或1,此时阶乘为1。
递归情况是n 大于1,此时需要计算n乘以(n-1)的阶乘。
由于(n-1)的阶乘可以通过递归调用来计算,因此可以使用递归算法来计算n的阶乘。
下面是一个使用递归算法计算阶乘的Python代码:```def factorial(n):if n == 0 or n == 1:return 1else:return n * factorial(n-1)```这个函数接受一个整数n作为参数,返回n的阶乘。
如果n等于0或1,函数返回1。
否则,函数返回n乘以(n-1)的阶乘,这个值通过递归调用factorial函数来计算。
递归算法的优点是它可以简化问题的解决方法,使代码更易于理解和维护。
但是,递归算法也有一些缺点。
递归算法通常需要更多的内存和处理时间,因为每个递归调用都需要保存一些状态信息。
此外,递归算法可能会导致栈溢出,因为每个递归调用都会在栈中创建一个新的帧。
在实际编程中,应该根据具体情况选择适当的算法。
如果问题可以通过递归算法简单地解决,那么递归算法是一个不错的选择。
但是,如果问题的规模很大,或者递归算法会导致栈溢出,那么应该考虑其他算法。
10000的阶乘的算法

10000的阶乘的算法(大数的阶乘)很多天没有更新自己的Blog了,前几天拿到一个题目.就是写一段程序计算10000的阶乘.当时我还以为这题目非常简单,没想到还是需要动点大脑的.花了将近半个小时才搞定,拿出来分享一下.为什么不能用普通的方法来写呢,比如说递归?在我的教科书上可是用的是递归呀?不知道你注意没有,如果是100的阶乘的话,其结果肯定是非常大的,以我们现有语言的数据类型肯定是没法使用的,就拿C来说,long型能存的下100的阶乘吗?未必.所以我就使用数组来存储结果的每一位,然后输出每一位不就是结果吗.那么具体怎样去做?首先确定结果的位数?如何确定呢?请看下面.2!=1*2<=10*103!=1*2*3<=10*10*10.......所以我们可以得出一个结论n!<=10n所以n!的位数可以这样计算:两边取对数,即log10n!<=log1010n两边n>=Log101+Log102+Log10 3+....Log10 n这样n!的位数肯定等于小于Log101+Log102+Log10 3+....Log10 n.以上是错误的正确的推断如下:可以将n!表示成10的次幂,即n!=10^M(10的M次方)则不小于M的最小整数就是 n!的位数,对该式两边取对数,有 =log10^n!即:M = log10^1+log10^2+log10^3...+log10^n循环求和,就能算得M值,该M是n!的精确位数。
位数的确定解决之后,就看看如何计算了.看看如下代码:1 int index=0;2 long carrier=0;3 double bitCount = 1;4 int begin = 0;56 for(index=2; index<=n; ++index)7 {8 long multiValue = 0;9 bitCount += log10((long double)index);10 if(arrValue[begin] == 0)11 begin++;1213 for(int j=begin; j<int(bitCount); ++j)14 {15 multiValue += (index*arrValue[j]);16 arrValue[j] = char(multiValue % 10);17 multiValue /= 10;18 }19 }这里就是计算的关键了.注意一下进位问题即可.所有代码如下:12/**///////////////////////////////////////////////////////////////// //////////3// Date created: 2005/07/124// Author: Confach Zhang5// Purpose: 计算n!的值6/**///////////////////////////////////////////////////////////////// //////////789using namespace std;10#include "StdAfx.h"11#include <iostream.h>12#include <conio.h>13#include <stdlib.h>14#include <math.h>15#include <stdio.h>16#include <iomanip.h>1718int GetNumber(); //输入 n19int GetBitLength(int n); //求n!的位数20char* Initialize(int); //初始化存储结果的值21void PrintValue(char *a,int size); //打印值到屏幕22void PrintValue(char *a,int size,char* fileName); //打印值到文件23char* GetValue(int val); //计算24char* SubGetValue(char* ,int);252627int main()28{29 int value=GetNumber();30 char fileName[16];31 int size=GetBitLength(value);32 char *pa = Initialize(size);34 //pa=GetValue();35 pa=GetValue(value);3637 PrintValue(pa,size);3839 //sprintf(fileName,"%s","10000!.txt");40 sprintf(fileName,"%d!.txt",value);4142 PrintValue(pa,size,fileName);43 delete []pa; //note:44 return 1;45}46//函数GetValue47// 求得计算结果48//返回结果49//History:50//1)char* GetValue()51//2)GetValue(int val)52// 参数:val 计算阶乘的值53char* GetValue(int val)54{55 //定义一个数组存储阶乘的值56 //首先得到10000!阶乘的位数57 int VALUE=val;58 int length=GetBitLength(VALUE);59 char *arrValue = new char[length];60 if(!arrValue) {61 cout <<"申请内存失败!" << endl;62 exit(1);63 }64 arrValue[0] = 1;65 for(int i=1; i<length; i++)66 arrValue[i] = 0;67 arrValue=SubGetValue(arrValue,VALUE);68 return arrValue;69}7071char* SubGetValue(char* arrValue,int n)72{73 int index=0;74 long carrier=0;75 double bitCount = 1;76 int begin = 0;78 for(index=2; index<=n; ++index)79 {80 long multiValue = 0;81 bitCount += log10((long double)index);82 if(arrValue[begin] == 0)83 begin++;8485 for(int j=begin; j<int(bitCount); ++j)86 {87 multiValue += (index*arrValue[j]);88 arrValue[j] = char(multiValue % 10);89 multiValue /= 10;90 }91 }92 return arrValue;93}9495//得到计算阶乘的值,此函数为新增96int GetNumber()97{98 int n;99 cout << "请输入要计算阶乘的n值: ";100 cin >> n;101 while(n < 0) {102 cout << "输入错误,请重新输入: ";103 cin >> n;104 }105 if(n == 0)106 exit(1);107 return n;108}109110//函数GetBitLength111// 求得计算结果的位数,本函数为新增加112//参数113// n 需要计算的阶乘的数114//返回结果的位数115int GetBitLength(int n)116{117 double sum = 1.0;118 for(int i=1; i<=n; i++)119 sum += log10((long double)i);120 return int(sum);122//-----------123//函数:Initialize124// 初始化存储结果的数组125//参数:126// size 数组的长度127//返回值128// 初始化后的数组129//-------------130char * Initialize(int size)131{132 char *arrValue = new char[size];133 if(!arrValue) {134 cout << size<<"太大,申请内存失败!" << endl; 135 exit(1);136 }137 arrValue[0] = 1;138 for(int i=1; i<size; i++)139 arrValue[i] = 0;140 return arrValue;141}142143//-----------144//函数:PrintValue145// 将结果输入到屏幕上146//参数:147// buff 存储结果的数组148// buffLen 数组的长度149// fileName 文件名150//-------------151void PrintValue(char *buff, int buffLen)152{153 int bit = 0;154 int nCol=0;155 for(int i=buffLen-1; i>=0; i--) {156 if(bit % 10 == 0)157 {158 cout << " " ;159 nCol++;160 if(nCol==10)cout<<endl;161 }162 cout << int (buff[i]);163 bit++;164 }165 cout << endl;166167}168//-----------169//函数:PrintValue170// 将结果输入到一个文件中171//参数:172// buff 存储结果的数组173// buffLen 数组的长度174// fileName 文件名175//-------------176177void PrintValue(char *buff,int buffLen,char *fileName) 178{179 int bit = 0;180 int nCol=0;181182 FILE *fp=NULL;183 //-----------------------------184185 if (fileName==NULL) return ;186 fp=fopen(fileName,"wt");187 if (fp==NULL)188 {189 printf("不能创建文件%s",fileName);190 return ;191 }192193 for(int i=buffLen-1; i>=0; i--)194 {195 fprintf(fp,"%d",int(buff[i]));196197 if(bit % 9 == 0)198 {199 fprintf(fp,"%s"," ");200 nCol++;201 if(nCol==8)202 {203 fprintf(fp,"%s","\n");204 nCol=0;205 }206 }207 bit++;208209 }210 fprintf(fp,"\n"); 211 fclose(fp);212}213好了,不说了.算法通过将输入的两个数,先进行反串,然后用指针分别置数的最低位,进行乘法,然后将余数保存到结构中,将进位暂先放到一个变量中,然后将被乘数往高位移动一个数字,再将其与乘数的最低位相乘,加上上一轮中的进位,即为该轮的值,按照同样的方法,可以将其进位、低位保存。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
高精度算法的基本思想,就是将无法直接处理的大整数,分割成若干可以直接处理的小整数段,把对大整数的处理转化为对这些小整数段的处理数据结构的选择每个小整数段保留尽量多的位使用Comp类型采用二进制表示法每个小整数段保留尽量多的位一个例子:计算两个15位数的和Ø方法一•分为15个小整数段,每段都是1位数,需要15次1位数加法Ø方法二•分为5个小整数段,每段都是3位数,需要5次3位数加法Ø方法三•Comp类型可以直接处理15位的整数,故1次加法就可以了Ø比较•用Integer计算1位数的加法和3位数的加法是一样快的•故方法二比方法一效率高•虽然对Comp的操作要比Integer慢,但加法次数却大大减少•实践证明,方法三比方法二更快使用Comp类型高精度运算中,每个小整数段可以用Comp类型表示Comp有效数位为19~20位求两个高精度数的和,每个整数段可以保留17位求高精度数与不超过m位整数的积,每个整数段可以保留18–m位求两个高精度数的积,每个整数段可以保留9位如果每个小整数段保留k位十进制数,实际上可以认为其只保存了1位10k进制数,简称为高进制数,称1位高进制数为单精度数采用二进制表示法采用二进制表示,运算过程中时空效率都会有所提高,但题目一般需要以十进制输出结果,所以还要一个很耗时的进制转换过程。
因此这种方法竞赛中一般不采用,也不在本文讨论之列.算法的优化高精度乘法的复杂度分析连乘的复杂度分析设置缓存分解质因数求阶乘二分法求乘幂分解质因数后的调整高精度乘法的复杂度分析计算n位高进制数与m位高进制数的积Ø需要n*m次乘法Ø积可能是n+m–1或n+m位高进制数连乘的复杂度分析(1)一个例子:计算5*6*7*8Ø方法一:顺序连乘•5*6=30,1*1=1次乘法•30*7=210,2*1=2次乘法•210*8=1680,3*1=3次乘法共6次乘法Ø方法二:非顺序连乘•5*6=30,1*1=1次乘法•7*8=56,1*1= 1次乘法•30*56=1680,2*2=4次乘法共6次乘法连乘的复杂度分析(2)若“n位数*m位数=n+m位数”,则n个单精度数,无论以何种顺序相乘,乘法次数一定为n(n-1)/2次Ø证明:•设F(n)表示乘法次数,则F(1)=0,满足题设•设k<n时,F(k)=k(k-1)/2,现在计算F(n)•设最后一次乘法计算为“k位数*(n-k)位数”,则•F(n)=F(k)+F(n-k)+k (n-k)=n(n-1)/2(与k的选择无关)设置缓存(1)一个例子:计算9*8*3*2Ø方法一:顺序连乘•9*8=72,1*1=1次乘法•72*3=216,2*1=2次乘法•216*2=432,3*1=3次乘法Ø方法二:非顺序连乘•9*8=72,1*1=1次乘法•3*2=6,1*1=1次乘法•72*6=432,2*1=2次乘法共6次乘法特点:n位数*m位数可能是n+m-1位数特点:n位数*m位数可能是n+m-1位数设置缓存(2)考虑k+t个单精度数相乘a1*a2*…*ak*ak+1*…*ak+tØ设a1*a2*…*ak结果为m位高进制数(假设已经算出)Øak+1*…*ak+t结果为1位高进制数Ø若顺序相乘,需要t次“m位数*1位数”,共mt次乘法Ø可以先计算ak+1*…*ak+t,再一起乘,只需要m+t次乘法在设置了缓存的前提下,计算m个单精度数的积,如果结果为n位数,则乘法次数约为n(n–1)/2次,与m关系不大–设S=a1a2… a m,S是n位高进制数–可以把乘法的过程近似看做,先将这m个数分为n组,每组的积仍然是一个单精度数,最后计算后面这n个数的积。
时间主要集中在求最后n个数的积上,这时基本上满足“n位数*m位数=n+m位数”,故乘法次数可近似的看做n(n-1)/2次设置缓存(3)缓存的大小Ø设所选标准数据类型最大可以直接处理t位十进制数Ø设缓存为k位十进制数,每个小整数段保存t–k位十进制数Ø设最后结果为n位十进制数,则乘法次数约为Øk/(n–k) ∑(i=1..n/k)i=(n+k)n/(2k(t–k)),其中k远小于nØ要乘法次数最少,只需k (t–k)最大,这时k=t/2Ø因此,缓存的大小与每个小整数段大小一样时,效率最高Ø故在一般的连乘运算中,可以用Comp作为基本整数类型,每个小整数段为9位十进制数,缓存也是9位十进制数分解质因数求阶乘例:10!=28*34*52*7Øn!分解质因数的复杂度远小于nlogn,可以忽略不计Ø与普通算法相比,分解质因数后,虽然因子个数m变多了,但结果的位数n没有变,只要使用了缓存,乘法次数还是约为n(n-1)/2次Ø因此,分解质因数不会变慢(这也可以通过实践来说明)Ø分解质因数之后,出现了大量求乘幂的运算,我们可以优化求乘幂的算法。
这样,分解质因数的好处就体现出来了二分法求乘幂二分法求乘幂,即:Øa2n+1=a2n*aØa2n=(a n)2Ø其中,a是单精度数复杂度分析Ø假定n位数与m位数的积是n+m位数Ø设用二分法计算a n需要F(n)次乘法ØF(2n)=F(n)+n2,F(1)=0Ø设n=2k,则有F(n)=F(2k)=∑(i=0..k–1)4i=(4k–1)/3=(n2–1)/3与连乘的比较Ø用连乘需要n(n-1)/2次乘法,二分法需要(n2–1)/3Ø连乘比二分法耗时仅多50%Ø采用二分法,复杂度没有从n2降到nlogn二分法求乘幂之优化平方算法怎样优化Ø(a+b)2=a2+2ab+b2Ø例:123452=1232*10000+452+2*123*45*100Ø把一个n位数分为一个t位数和一个n-t位数,再求平方怎样分Ø设求n位数的平方需要F(n)次乘法ØF(n)=F(t)+F(n-t)+t(n-t),F(1)=1Ø用数学归纳法,可证明F(n)恒等于n(n+1)/2Ø所以,无论怎样分,效率都是一样Ø将n位数分为一个1位数和n–1位数,这样处理比较方便二分法求乘幂之复杂度分析复杂度分析Ø前面已经求出F(n)=n(n+1)/2,下面换一个角度来处理ØS2=(∑(0≤i<n)a i10i)2=∑(0≤i<n)a i2102i+2∑(0≤i<j<n)a i a j10i+jØ一共做了n+C(n,2)=n(n+1)/2次乘法运算Ø普通算法需要n2次乘法,比改进后的慢1倍改进求乘幂的算法Ø如果在用改进后的方法求平方,则用二分法求乘幂,需要(n+4)(n–1)/6次乘法,约是连乘算法n(n–1) /2的三分之一分解质因数后的调整(1)为什么要调整Ø计算S=211310,可以先算211,再算310,最后求它们的积Ø也可以根据S=211310=610*2,先算610,再乘以2即可Ø两种算法的效率是不同的分解质因数后的调整(2)什么时候调整Ø计算S=a x+k b x=(ab)x a kØ当k<xlog a b时,采用(ab)x a k比较好,否则采用a x+k b x更快Ø证明:•可以先计算两种算法的乘法次数,再解不等式,就可以得到结论•也可以换一个角度来分析。
其实,两种算法主要差别在最后一步求积上。
由于两种方法,积的位数都是一样的,所以两个因数的差越大,乘法次数就越小•∴当a x b x–a k>a x+k–b x时,选用(ab)x a k,反之,则采用a x+k b x。
•∴a x b x–a k>a x+k–b x•∴(b x–a k)(a x+1)>0•∴b x>a k•这时k<xlog a b总结内容小结Ø用Comp作为每个小整数段的基本整数类型Ø采用二进制优化算法Ø高精度连乘时缓存和缓存的设置Ø改进的求平方算法Ø二分法求乘幂Ø分解质因数法求阶乘以及分解质因数后的调整应用Ø高精度求乘幂(平方)Ø高精度求连乘(阶乘)Ø高精度求排列组合结束语求N!的高精度算法本身并不难,但我们仍然可以从多种角度对它进行优化。
其实,很多经典算法都有优化的余地。
我们自己编写的一些程序也不例外。
只要用心去优化,说不准你就想出更好的算法来了。
也许你认为本文中的优化毫无价值。
确实是这样,竞赛中对高精度的要求很低,根本不需要优化。
而我以高精度算法为例,不过想谈谈如何优化一个算法。
我想说明的只有一点:算法是可以优化的。