编程中的优化算法问题
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
旧代码: for (i = 0; i < 100; i++) {
do_stuff(i); }
新代码: for (i = 0; i < 100; ) {
do_stuff(i); i++; do_stuff(i); i++; do_stuff(i); i++; do_stuff(i); i++;
do_stuff(i); i++; do_stuff(i); i++; do_stuff(i); i++; do_stuff(i); i++; do_stuff(i); i++; do_stuff(i); i++; }
组
内容:
A.什么是算法? 所谓算法,是指对解题方案的一个准确而完整的描述。算法不等于程序,也不等于计算方法;
程序是作为算法的一种描述,但是程序通常还需考虑很多与方法和分析无关的细节问题,这是因 为在编写程序时要受到计算机系统运行环境的限制。
通常,程序的编制不可能优于算法的设计。
B.什么是算法优化? 算法优化,优化是一个动词,是对某个算法的具体优化。所有的算法都是有优化的空间的。
比如动态归划算法,有斜率优化,四边形不等式优化,还有图论的算法,如 SAP 算法,这个可以 用间隙优化,变成 ISAP。还有高精度算法,大数相加的,可以有进制优化,常数优化,能不用取 余的就不用取余,能用加法的不用乘法,能用减法的不用除法……
C.算法优化的意义有哪些? 1. 算法优化的过程是学习思维的过程
宏内联的例子: 旧代码: int foo(a, b) {
a = a - b; b++;
三
a = a * b; return a; }
新代码: #define foo(a, b) (((a)-(b)) * ((b)+1))
注意最外层括号是必须的,因为当宏在表达式中展开时,你不知道表达式里还有没有比乘法级 别更高的运算.
8.循环转置 有些机器对 JNZ(为 0 转移)有特别的指令处理,速度非常快,如果你的循环对方向不敏感,可以
可以看出,新代码里比较指令由 100 次降低为 10 次,循环时间节约了 90%.
四
不过注意:对于中间变量或结果被更改的循环,编译程序往往拒绝展开,(怕担责任呗),这时候 就需要你自己来做展开工作了.
还有一点请注意,在有内部指令 cache 的 CPU 上(如 MMX 芯片),因为循环展开的代码很大,往往 cache 溢出,这时展开的代码会频繁地在 CPU 的 cache 和内存之间调来调去,又因为 cache 速度很 高,所以此时循环展开反而会变慢.还有就是循环展开会影响矢量运算优化.
学习数学实质上就是学习思维。也就是说数学教育的目的不仅仅是要让学生掌握数学知识(包 括计算技能),更重要的要让学生学会数学地思维。算法多样化具有很大的教学价值,学生在探究 算法多样化的过程中,培养了思维的灵活性,发展了学生的创造性。在认识算法多样化的教学价 值的同时,我们也认识到不同算法的思维价值是不相等的。要充分体现算法多样化的教育价值, 教师就应该积极引导学生优化算法,把优化算法的过程看作是又一次发展学生思维、培养学生能 力的机会,把优化算法变成学生又一次主动建构的学习活动。让学生在优化算法的过程中,通过 对各种算法的比较和分析,进行评价,不仅评价其正确性——这样做对吗?而且评价其合理性—
D.算法优化
1.选择一个更好的算法:
应该熟悉算法语言,知道各种算法的优缺点,一般很多计算机资料文本上有介绍,应该能够看
得懂算法描述.
这里是一些明显可以通用的替换:
慢的算法
替换成
顺序查找
Baidu Nhomakorabea
二分法查找或乱序查找
插入排序或冒泡排序
快速排序,合并排序,根(radix)排序
二
还要选择一种合适的数据结构,比如你在一堆随机存放 的数中使用了大量的插入和删除指令,那使用链表要快得多.如果你要做二 分法查找,那提前排下序非常重要.
一些警告: 1.无限制地使用宏可以使代码爆炸,程序会很快消耗完你所有的资源,包 括物理内存,最 后系统要么崩溃,要么把你的代码放到虚拟内存(磁盘上)中去,那你再怎么优化也没用了 2.C 的宏每次调用都要对参数赋值,如果参数很多很复杂,那光赋值就要消耗大量的 CPU 时间, 效果还不如不用宏 3.因为宏允许包含很复杂的表达式,所以编译程序会非常辛苦,为了使自己不至于完全发疯, 一般编译程序对宏能包含的字符数都有一个限制,注意别犯规. 4.一旦用了宏,prof 程序也跟着糊涂起来了,这是它说的话可信度可不高
意识是行动的向导,有些学生因为思维的惰性而表现出算法单一的状态。明明自己的算法很 繁琐,但是却不愿动脑做深入思考,仅仅满足于能算出结果就行。要提高学生的思维水平,我们 就应该有意识的激发学生思维和生活的联系,帮助他们去除学生思维的惰性,鼓励他们从多个角 度去思考问题,然后择优解决;鼓励他们不能仅仅只关注于自己的算法,还要认真倾听他人的思 考、汲取他人的长处;引导他们去感受各种不同方法的之间联系和合理性,引导他们去感受到数 学学科本身所特有的简洁性。再算法优化的过程中就是要让学生感受计算方法提炼的过程,体会 其中的数学思想方法,更在于让学生思维碰撞,并形成切合学生个人实际的计算方法,从中培养 学生的数学意识,使学生能自觉地运用数学思想方法来分析事物,解决问题。这样的过程不仅是 对知识技能的一种掌握和巩固,而且可以使学生的思维更开阔、更深刻。 3. 算法优化是学生个体学习、体验感悟、加深理解的过程
小学数学是整个数学体系的基础,是一个有着严密逻辑关系的子系统。算法教学是小学数学 教学的一部分,它不是一个孤立的教学点。从某一教学内容来说,也许没有哪一种算法是最好的、 最优的,但从算法教学的整个系统来看,必然有一种方法是最好的、最优的,是学生后继学习所 必需掌握的。在算法多样化的过程中,当学生提出各种算法后,教师要及时引导学生进行比较和 分析,在比较和分析的过程中感受不同策略的特点,领悟不同方法的算理,分析不同方法的优劣, 做出合理的评价,从而选择具有普遍意义的、简捷的、并有利于后继学习的最优方法。 5. 优化也是数学学科发展的动力
5.内联(内嵌) gcc(使用-finline-functions 参数),还有一些别的编译器可以在最高级优化中内联一些小的
函数.K&C 编译器则只有在库函数是用汇编写成的时候才内联,C++编译器普遍支持内联函数.不过 把 C 函数写成宏也能达到加速的作用,不过必须是在程序完全除错之后,因为绝大多数除错程序不 支持宏除错.
6.循环展开 这是经典的速度优化,但许多编译程序(如 gcc -funroll-loops)能自动完成这个事,所以现在
你自己来优化这个显得效果不明显.(这里说一句,云风工作室的云风朋友曾来信和东楼专门探讨 过这个问题,他根据自己在 DJGPP 的经验认定循环展开无效,东楼猜测可能就是因为 gcc 在编译时 自动进行了展开,所以手工展开已经没多大效果了.但这个方法总是对的).
新代码: for (i = 0; i < MAX; i++) /* initialize 2d array to 0's */ {
for (j = 0; j < MAX; j++) a[i][j] = 0.0;
a[i][i] = 1.0; /* put 1's along the diagonal */ }
4.理解你的编译程序选项 许多编译程序有几级优化选项,注意使用最优化的一项,特别注意 gcc,优化选项非常多,小心
使用,别弄得适得其反.通常情况下一旦选用最高级优化,编译程序会近乎病态地追求代码优化,精 简指令,(如 DJGPP 的-O3),但少数情况下,这会影响程序的正确性,这是你只有改自己的程序啦.不 过也有这种情况,就是一些参数会影响优化的程序,但是不会影响普通程序,这时只有具体情况具 体分析了.
适当的时候尽量减小每个函数的代码量,不过也别走极端,别为了优化把一个函数写成 10 页 纸的一堆函数,那编译器倒高兴了,可人发疯了.
3.透视你的程序 一个程序写出来,凭直觉就应该感觉出哪些地方快,哪些地方慢,一般说来,最快的运算就是分
配一块内存,给指针赋值,还有就是两个整数的加法运算,别的都有点慢,最慢的就要数打开文件啦, 打开新的进程啦,读写一大块内存啦,寻找啦,排序啦等等,别看这帮虾子指令都只要几个微秒,可 成百上千的杀将过来,东楼可受不了.一定不能让这帮虾子进循环,干了它.
2.写一些清晰,可读性好并且简单的代码 一个人容易看得懂的程序同样也容易被编译器读懂.一个大而复杂的表达式往往会把编译器
脑袋都弄大,为了防止自己发疯,编译器往往放弃对这段代码的优化.但绝对不会向你报告,出于维 护自己面子起见,东楼发现所有的编译器都只会向你报告它优化了多少,而决不会报告它干不了的 有多少,东楼就亲眼见到一个瓜编译器因为一个表达式弄昏了头,把整个模块的优化都放弃了,回 来居然还恬不知耻的报告优化非常顺利,整个儿一个报喜不报忧.
一
—这样做有道理吗?还要评价其科学性——这样做是最好的吗?这样的优化过程,对学生思维品 质的提高无疑是十分有用的,学生在讨论、交流和反思的择优过程中逐步学会“多中择优,优中 择简”的数学思想方法。教师在引导学生算法优化的过程中,帮助学生梳理思维过程,总结学习 方法,养成思维习惯,形成学习能力,长此以往学生的思维品质一定能得到很大的提高。 2. 在算法优化的过程中培养学生算法优化的意识和习惯
研究性学习:编程中的优化算法问题
课题组:高一十一班数学研究性学习小组
研究内容:编程中的优化算法问题
指导老师:张永平
组长:杨帆
组员:沙彦刚 王文琦 高天龙 李妍 任瑞荣 陈文文 王小路
感谢为本论文提供资料的所有网站,专家和学者以及指导老师张永平
申明:(本论文绝不允许有商业用途,仅供交流、学习之用)
——高一十一班数学研究性学习小
这是经常犯的一个错误: if (x != 0) x = 0; 程序的原意是当 x 等于 0 时,节约时间不执行赋值操作,可你别忘了,赋值语句才是最快的,那 还不如直接写成下面的语句更来劲. x = 0; 还有就是一些神勇的大虾,非得等到编译器把代码输出成汇编语言级然后拿着计算器一行行 加汇编指令的个数和周期数,才算优化完成了,不过可别忘了,最后一次优化不是 obj 代码级的,而 是由 link 程序完成的,这没多大用.
数学是一门基础学科,是一门工具学科,它的应用十分广泛。数学之所以有如此广泛的应用, 就是因为数学总是要求人们不断寻求使问题获得解决的捷径,在众多复杂的问题中,不断寻找最 优、最简捷的解决问题的方法;就是因为在每门学科的研究中,应用了数学方法后,其研究过程 得到优化,提高了研究的效率和质量。计算是数学的主要内容,算法的优化当然也不例外。所以 数学的广泛应用全得益于优化,优化是数学的灵魂。因此,数学的发展过程就是一个不断优化的 过程,它的每一个成果都是后人不断优化前人研究成果的结果。优化是数学的精髓,是数学发展 不竭的动力,数学就是在不断优化的过程中得到发展的。
算法多样化是每一个学生经过自己独立的思考和探索,各自提出的方法,从而在群体中出现 了许多种算法。因此,算法多样化是群体学习能力的表现,是学生集体的一题多解,而不是学生 个体的多种算法。而算法的优化是让学生在群体比较的过程中优化,通过交流各自得算法,学生 可以互相借鉴,互相吸收,互相补充,在个体感悟的前提下实施优化。因为优化是学生对知识结 构的再构建过程,是发自学生内心的行为和自主的活动。但是,在实施算法最优化教学时应给学 生留下一定的探索空间,以及一个逐渐感悟的过程。让学生在探索中感悟,在比较中感悟,在选 择中感悟。这样,才利于发展学生独立思考能力和创造能力。 4. 优化算法也是学生后继学习的需要
7.循环嵌套 把相关循环放到一个循环里,也会加快速度. 旧代码: for (i = 0; i < MAX; i++) /* initialize 2d array to 0's */ for (j = 0; j < MAX; j++) a[i][j] = 0.0; for (i = 0; i < MAX; i++) /* put 1's along the diagonal */ a[i][i] = 1.0;
do_stuff(i); }
新代码: for (i = 0; i < 100; ) {
do_stuff(i); i++; do_stuff(i); i++; do_stuff(i); i++; do_stuff(i); i++;
do_stuff(i); i++; do_stuff(i); i++; do_stuff(i); i++; do_stuff(i); i++; do_stuff(i); i++; do_stuff(i); i++; }
组
内容:
A.什么是算法? 所谓算法,是指对解题方案的一个准确而完整的描述。算法不等于程序,也不等于计算方法;
程序是作为算法的一种描述,但是程序通常还需考虑很多与方法和分析无关的细节问题,这是因 为在编写程序时要受到计算机系统运行环境的限制。
通常,程序的编制不可能优于算法的设计。
B.什么是算法优化? 算法优化,优化是一个动词,是对某个算法的具体优化。所有的算法都是有优化的空间的。
比如动态归划算法,有斜率优化,四边形不等式优化,还有图论的算法,如 SAP 算法,这个可以 用间隙优化,变成 ISAP。还有高精度算法,大数相加的,可以有进制优化,常数优化,能不用取 余的就不用取余,能用加法的不用乘法,能用减法的不用除法……
C.算法优化的意义有哪些? 1. 算法优化的过程是学习思维的过程
宏内联的例子: 旧代码: int foo(a, b) {
a = a - b; b++;
三
a = a * b; return a; }
新代码: #define foo(a, b) (((a)-(b)) * ((b)+1))
注意最外层括号是必须的,因为当宏在表达式中展开时,你不知道表达式里还有没有比乘法级 别更高的运算.
8.循环转置 有些机器对 JNZ(为 0 转移)有特别的指令处理,速度非常快,如果你的循环对方向不敏感,可以
可以看出,新代码里比较指令由 100 次降低为 10 次,循环时间节约了 90%.
四
不过注意:对于中间变量或结果被更改的循环,编译程序往往拒绝展开,(怕担责任呗),这时候 就需要你自己来做展开工作了.
还有一点请注意,在有内部指令 cache 的 CPU 上(如 MMX 芯片),因为循环展开的代码很大,往往 cache 溢出,这时展开的代码会频繁地在 CPU 的 cache 和内存之间调来调去,又因为 cache 速度很 高,所以此时循环展开反而会变慢.还有就是循环展开会影响矢量运算优化.
学习数学实质上就是学习思维。也就是说数学教育的目的不仅仅是要让学生掌握数学知识(包 括计算技能),更重要的要让学生学会数学地思维。算法多样化具有很大的教学价值,学生在探究 算法多样化的过程中,培养了思维的灵活性,发展了学生的创造性。在认识算法多样化的教学价 值的同时,我们也认识到不同算法的思维价值是不相等的。要充分体现算法多样化的教育价值, 教师就应该积极引导学生优化算法,把优化算法的过程看作是又一次发展学生思维、培养学生能 力的机会,把优化算法变成学生又一次主动建构的学习活动。让学生在优化算法的过程中,通过 对各种算法的比较和分析,进行评价,不仅评价其正确性——这样做对吗?而且评价其合理性—
D.算法优化
1.选择一个更好的算法:
应该熟悉算法语言,知道各种算法的优缺点,一般很多计算机资料文本上有介绍,应该能够看
得懂算法描述.
这里是一些明显可以通用的替换:
慢的算法
替换成
顺序查找
Baidu Nhomakorabea
二分法查找或乱序查找
插入排序或冒泡排序
快速排序,合并排序,根(radix)排序
二
还要选择一种合适的数据结构,比如你在一堆随机存放 的数中使用了大量的插入和删除指令,那使用链表要快得多.如果你要做二 分法查找,那提前排下序非常重要.
一些警告: 1.无限制地使用宏可以使代码爆炸,程序会很快消耗完你所有的资源,包 括物理内存,最 后系统要么崩溃,要么把你的代码放到虚拟内存(磁盘上)中去,那你再怎么优化也没用了 2.C 的宏每次调用都要对参数赋值,如果参数很多很复杂,那光赋值就要消耗大量的 CPU 时间, 效果还不如不用宏 3.因为宏允许包含很复杂的表达式,所以编译程序会非常辛苦,为了使自己不至于完全发疯, 一般编译程序对宏能包含的字符数都有一个限制,注意别犯规. 4.一旦用了宏,prof 程序也跟着糊涂起来了,这是它说的话可信度可不高
意识是行动的向导,有些学生因为思维的惰性而表现出算法单一的状态。明明自己的算法很 繁琐,但是却不愿动脑做深入思考,仅仅满足于能算出结果就行。要提高学生的思维水平,我们 就应该有意识的激发学生思维和生活的联系,帮助他们去除学生思维的惰性,鼓励他们从多个角 度去思考问题,然后择优解决;鼓励他们不能仅仅只关注于自己的算法,还要认真倾听他人的思 考、汲取他人的长处;引导他们去感受各种不同方法的之间联系和合理性,引导他们去感受到数 学学科本身所特有的简洁性。再算法优化的过程中就是要让学生感受计算方法提炼的过程,体会 其中的数学思想方法,更在于让学生思维碰撞,并形成切合学生个人实际的计算方法,从中培养 学生的数学意识,使学生能自觉地运用数学思想方法来分析事物,解决问题。这样的过程不仅是 对知识技能的一种掌握和巩固,而且可以使学生的思维更开阔、更深刻。 3. 算法优化是学生个体学习、体验感悟、加深理解的过程
小学数学是整个数学体系的基础,是一个有着严密逻辑关系的子系统。算法教学是小学数学 教学的一部分,它不是一个孤立的教学点。从某一教学内容来说,也许没有哪一种算法是最好的、 最优的,但从算法教学的整个系统来看,必然有一种方法是最好的、最优的,是学生后继学习所 必需掌握的。在算法多样化的过程中,当学生提出各种算法后,教师要及时引导学生进行比较和 分析,在比较和分析的过程中感受不同策略的特点,领悟不同方法的算理,分析不同方法的优劣, 做出合理的评价,从而选择具有普遍意义的、简捷的、并有利于后继学习的最优方法。 5. 优化也是数学学科发展的动力
5.内联(内嵌) gcc(使用-finline-functions 参数),还有一些别的编译器可以在最高级优化中内联一些小的
函数.K&C 编译器则只有在库函数是用汇编写成的时候才内联,C++编译器普遍支持内联函数.不过 把 C 函数写成宏也能达到加速的作用,不过必须是在程序完全除错之后,因为绝大多数除错程序不 支持宏除错.
6.循环展开 这是经典的速度优化,但许多编译程序(如 gcc -funroll-loops)能自动完成这个事,所以现在
你自己来优化这个显得效果不明显.(这里说一句,云风工作室的云风朋友曾来信和东楼专门探讨 过这个问题,他根据自己在 DJGPP 的经验认定循环展开无效,东楼猜测可能就是因为 gcc 在编译时 自动进行了展开,所以手工展开已经没多大效果了.但这个方法总是对的).
新代码: for (i = 0; i < MAX; i++) /* initialize 2d array to 0's */ {
for (j = 0; j < MAX; j++) a[i][j] = 0.0;
a[i][i] = 1.0; /* put 1's along the diagonal */ }
4.理解你的编译程序选项 许多编译程序有几级优化选项,注意使用最优化的一项,特别注意 gcc,优化选项非常多,小心
使用,别弄得适得其反.通常情况下一旦选用最高级优化,编译程序会近乎病态地追求代码优化,精 简指令,(如 DJGPP 的-O3),但少数情况下,这会影响程序的正确性,这是你只有改自己的程序啦.不 过也有这种情况,就是一些参数会影响优化的程序,但是不会影响普通程序,这时只有具体情况具 体分析了.
适当的时候尽量减小每个函数的代码量,不过也别走极端,别为了优化把一个函数写成 10 页 纸的一堆函数,那编译器倒高兴了,可人发疯了.
3.透视你的程序 一个程序写出来,凭直觉就应该感觉出哪些地方快,哪些地方慢,一般说来,最快的运算就是分
配一块内存,给指针赋值,还有就是两个整数的加法运算,别的都有点慢,最慢的就要数打开文件啦, 打开新的进程啦,读写一大块内存啦,寻找啦,排序啦等等,别看这帮虾子指令都只要几个微秒,可 成百上千的杀将过来,东楼可受不了.一定不能让这帮虾子进循环,干了它.
2.写一些清晰,可读性好并且简单的代码 一个人容易看得懂的程序同样也容易被编译器读懂.一个大而复杂的表达式往往会把编译器
脑袋都弄大,为了防止自己发疯,编译器往往放弃对这段代码的优化.但绝对不会向你报告,出于维 护自己面子起见,东楼发现所有的编译器都只会向你报告它优化了多少,而决不会报告它干不了的 有多少,东楼就亲眼见到一个瓜编译器因为一个表达式弄昏了头,把整个模块的优化都放弃了,回 来居然还恬不知耻的报告优化非常顺利,整个儿一个报喜不报忧.
一
—这样做有道理吗?还要评价其科学性——这样做是最好的吗?这样的优化过程,对学生思维品 质的提高无疑是十分有用的,学生在讨论、交流和反思的择优过程中逐步学会“多中择优,优中 择简”的数学思想方法。教师在引导学生算法优化的过程中,帮助学生梳理思维过程,总结学习 方法,养成思维习惯,形成学习能力,长此以往学生的思维品质一定能得到很大的提高。 2. 在算法优化的过程中培养学生算法优化的意识和习惯
研究性学习:编程中的优化算法问题
课题组:高一十一班数学研究性学习小组
研究内容:编程中的优化算法问题
指导老师:张永平
组长:杨帆
组员:沙彦刚 王文琦 高天龙 李妍 任瑞荣 陈文文 王小路
感谢为本论文提供资料的所有网站,专家和学者以及指导老师张永平
申明:(本论文绝不允许有商业用途,仅供交流、学习之用)
——高一十一班数学研究性学习小
这是经常犯的一个错误: if (x != 0) x = 0; 程序的原意是当 x 等于 0 时,节约时间不执行赋值操作,可你别忘了,赋值语句才是最快的,那 还不如直接写成下面的语句更来劲. x = 0; 还有就是一些神勇的大虾,非得等到编译器把代码输出成汇编语言级然后拿着计算器一行行 加汇编指令的个数和周期数,才算优化完成了,不过可别忘了,最后一次优化不是 obj 代码级的,而 是由 link 程序完成的,这没多大用.
数学是一门基础学科,是一门工具学科,它的应用十分广泛。数学之所以有如此广泛的应用, 就是因为数学总是要求人们不断寻求使问题获得解决的捷径,在众多复杂的问题中,不断寻找最 优、最简捷的解决问题的方法;就是因为在每门学科的研究中,应用了数学方法后,其研究过程 得到优化,提高了研究的效率和质量。计算是数学的主要内容,算法的优化当然也不例外。所以 数学的广泛应用全得益于优化,优化是数学的灵魂。因此,数学的发展过程就是一个不断优化的 过程,它的每一个成果都是后人不断优化前人研究成果的结果。优化是数学的精髓,是数学发展 不竭的动力,数学就是在不断优化的过程中得到发展的。
算法多样化是每一个学生经过自己独立的思考和探索,各自提出的方法,从而在群体中出现 了许多种算法。因此,算法多样化是群体学习能力的表现,是学生集体的一题多解,而不是学生 个体的多种算法。而算法的优化是让学生在群体比较的过程中优化,通过交流各自得算法,学生 可以互相借鉴,互相吸收,互相补充,在个体感悟的前提下实施优化。因为优化是学生对知识结 构的再构建过程,是发自学生内心的行为和自主的活动。但是,在实施算法最优化教学时应给学 生留下一定的探索空间,以及一个逐渐感悟的过程。让学生在探索中感悟,在比较中感悟,在选 择中感悟。这样,才利于发展学生独立思考能力和创造能力。 4. 优化算法也是学生后继学习的需要
7.循环嵌套 把相关循环放到一个循环里,也会加快速度. 旧代码: for (i = 0; i < MAX; i++) /* initialize 2d array to 0's */ for (j = 0; j < MAX; j++) a[i][j] = 0.0; for (i = 0; i < MAX; i++) /* put 1's along the diagonal */ a[i][i] = 1.0;