浅谈优化程序性能(上)

前言

我们知道,多项式定义为:

在几何学中,多项式是最简单的平滑曲线。简单是指它仅由乘法及加法构成,平滑是因为它类同口语中的平滑,以数学术语来说,它是无限可微,即它的所有高次微分都存在。事实上,多项式的微分也是多项式。简单及平滑的特点,使多项式在数值分析、图论,以及电脑绘图等,都发挥极大的作用。多项式求值是解决许多问题的核心技术。以数值分析为例,多项式函数常常用作对数学库中的三角函数求近似值。

现在,让我们来用 C 语言写一个对多项式求值的函数吧。

直接的算法

直接按照多项式的定义使用循环求值:


1

2

3

4

5

6

double poly(double a[], double x)

{

  double result
= 0, p = 1;

  for (int i
= 0; i < N; i++, p *= x) result += a[i] * p;

  return result;

}

这个算法需要执行 2N 个乘法和 N 个加法。

秦九韶算法(Horner‘s method)

我们可以通过使用秦九韶算法,或者被大多数外国人以及一些中国人称为 Horner‘s method 的算法,来减少乘法的数量:

相应的 C 语言程序如下所示:


1

2

3

4

5

6

double polyh(double a[], double x)

{

  double result
= 0;

  for (int i
= N - 1; i >= 0; i--) result = result * x + a[i];

  return result;

}

这个算法需要执行 N 个乘法和 N 个加法。乘法的数量是原始算法的一半。

看来,通过使用秦九韶算法,我们大大地优化了程序的性能。

且慢,还是以事实说话吧,让我们来作一些测试吧。

测试程序

下面就是比较这两个算法性能优劣的测试程序 poly.c :


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

#include
<stdio.h>

#include
<time.h>

#define
N 23456789

void initialize(double a[])

{

  for (int i
= 0; i < N; i++) a[i] = i - 12345678.9012345;

}

double poly(double a[], double x)

{

  double result
= 0, p = 1;

  for (int i
= 0; i < N; i++, p *= x) result += a[i] * p;

  return result;

}

double polyh(double a[], double x)

{

  double result
= 0;

  for (int i
= N - 1; i >= 0; i--) result = result * x + a[i];

  return result;

}

int main(int argc, char *argv[])

{

  static double a[N];

  initialize(a);

  double result
= 0, (*func)(
double*, double)
= (argc > 1) ? polyh : poly;

  clock_t elapsed
clock();

  for (int i
= 0; i < 1234; i++) result += func(a, 2.34 / (i - 1234567) - 1);

  elapsed
clock()
- elapsed;

  printf("%p
%g %11f\n"
,
func, result, (
double)elapsed
/ CLOCKS_PER_SEC);

}

这个测试程序通过对一个二十多万项的多项式用不同的自变量值求值一千多遍来比较两个算法的优劣。测试程序中的各项参数经过精心选择,不会在求值过程中造成浮点溢出。在 C 语言中,每个双精度浮点数占用八个字节,所以这个测试程序大约需要一百八十兆字节的内存空间来运行。

测试结果

我们在 32-bit Windows 操作系统和 64-bit Linux 操作系统下均进行了测试,结果如下所示:

D:\work> cl /O2 poly.cpp
用于 80x86 的 Microsoft (R) 32 位 C/C++ 优化编译器 16.00.40219.01 版
版权所有(C) Microsoft Corporation。保留所有权利。

poly.cpp
Microsoft (R) Incremental Linker Version 10.00.40219.01
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:poly.exe
poly.obj

D:\work> poly
00871000 1.4271e+029  107.531000
D:\work> poly h
00871080 1.4271e+029  127.686000
D:\work> poly h
00871080 1.4271e+029  127.686000
D:\work> poly
00871000 1.4271e+029  106.860000
D:\work> poly
00871000 1.4271e+029  107.935000
D:\work> poly h
00871080 1.4271e+029  128.662000
[email protected]:~/work> gcc -std=c99 -O2 poly.c
[email protected]:~/work> ./a.out
0x400640 1.4271e+29  125.240000
[email protected]:~/work> ./a.out
0x400640 1.4271e+29  124.820000
[email protected]:~/work> ./a.out h
0x400680 1.4271e+29  160.890000
[email protected]:~/work> ./a.out h
0x400680 1.4271e+29  162.210000
[email protected]:~/work> ./a.out
0x400640 1.4271e+29  125.450000
[email protected]:~/work> ./a.out h
0x400680 1.4271e+29  162.230000

上述运行结果中,第一栏是 func 变量的值,表示指向 poly 或 polyh 函数的指针。第二栏是对多项式求值结果的总和。第三栏是运行时间,单位是秒。总结一下,如下表所示:

操作系统 Windows (32-bit) Linux (64-bit)
所用算法 直接的 秦九韶 直接的 秦九韶
函数地址 00871000 00871080 0x400640 0x400680
计算结果 1.4271e+029 1.4271e+029 1.4271e+29 1.4271e+29
1 107.531 127.686 125.24 160.89
2 106.860 127.686 124.82 162.21
3 107.935 128.662 125.45 162.23
平均(秒) 107.442 128.011 125.17 161.78

测试说明

是不是非常意外?无论是在 32-bit Windows 操作系统,还是在 64-bit Linux 操作系统中测试,多次测试结果都表明秦九韶算法比原始的算法慢,同一算法在同一操作系统中的多次运行的所需的时间也很接近。由于我们使用的 Linux 操作系统是 64-bit 的,同一算法比在 32-bit 的 Windows 操作系统运行要稍微慢一点。所有的测试结果中,无论是用哪种算法,还是在不同的操作系统中,对多项式求值结果的总和都是相同的,这是预料之中,如果不同就有问题了。

下图是测试程序运行时的内存和 CPU 使用情况,由于是双核的 CPU,测试程序运行时 CPU 使用率为百分之五十左右:

可以看出进程数为83个,内存使用965MB。测试程序运行完毕,进程数减少一个,内存也降到795MB:

下图是在 Linux 操作系统中测试程序的运行状况,由于 VirtualBox 只给 Linux 操作系统分配一个 CPU,所以测试程序运行时 CPU 占用接近百分之百,内存占用大约 179 MB,如下图所示:

测试环境

本次测试是在 Dell inspiron 1520 本本上运行的,该本本只有一个 CPU,是双核心的 Intel Core2 Duo。安装了 Windows Vista Hoem Premium SP2 (32-bit) 操作系统。

在 Oracle VM VirtualBox 上运行的 openSuSE 12.1 (64-bit) 操作系统:

版权声明:本文为博主http://www.zuiniusn.com原创文章,未经博主允许不得转载。

时间: 2024-08-02 00:25:57

浅谈优化程序性能(上)的相关文章

浅谈优化程序性能(下)

前言 在上一篇随笔中,我们谈到最小化一个计算中的操作数量不一定会提高它的性能.现在,就让我们来解开为什么会出现这种情况的原因吧. 处理器体系结构 在计算机的处理器中,处理一条指令包括很多操作,可以分为取指(fetch).译码(decode).执行(execute).访存(memory).写回(write back)和更新程序计数器(PC update)等几个阶段.这些阶段可以在流水线上同时进行,如下图所示: 上图中,F.D.E.M 和 W 分别代表上述五个阶段.当然,现代的处理器比这个示例要复杂

浅谈 Python 程序和 C 程序的整合

源地址:http://www.ibm.com/developerworks/cn/linux/l-cn-pythonandc/ 概览 Python 是一种用于快速开发软件的编程语言,它的语法比较简单,易于掌握,但存在执行速度慢的问题,并且在处理某些问题时存在不足,如对计算机硬件系统的访问,对媒体文件的访问等.而作为软件开发的传统编程语言—— C 语言,却能在这些问题上很好地弥补 Python 语言的不足.因此,本文通过实例研究如何在 Python 程序中整合既有的 C 语言模块,包括用 C 语言

浅谈mapreduce程序部署

尽管我们在虚拟机client上能非常快通过shell命令,进行运行一些已经封装好实例程序,可是在应用中还是是自己敲代码,然后部署到server中去,以下,我通过程序进行浅谈一个程序的部署过程. 在启动Hadoop之后,然后把程序达成可运行的jar包,并把对应的第三方jar包 包括进去.运行hadoop    jar   XXX. +驱动名称. package com.mapred; import java.io.IOException; import java.io.PrintStream; i

深入理解计算机系统(5.1)------优化程序性能

你能获得的对程序最大的加速比就是当你第一次让它工作起来的时候. 在讲解如何优化程序性能之前,我们首先要明确写程序最主要的目标就是使它在所有可能的情况下都能正常工作,一个运行的很快的程序但是却是错误的结果是没有任何用处的,所以我们在进行程序性能优化之前,首先要保证程序能正常运行,且结果是我们需要的. 而且在很多情况下,让程序跑的更快是我们必须要解决的问题.比如一个程序要实时处理视频帧或者网络包,那么一个运行的很慢的程序就不能解决此问题.再比如一个计算任务计算量非常大,需要数日或者数周,如果我们哪怕

【菜鸟学php】小菜鸟由帝国备份王在Wamp环境下打开500错误浅谈PHP程序员

===================问题情况描述=================== 小弟一直在玩discuz论坛开源程序,这个论坛程序经常涉及到论坛搬家的问题. 今天我在本地Wamp环境下,用开源软件帝国备份王2010进行数据库备份数据,结果打开发现报错500! 这真是坑爹了,回想下以前自己使用这个开源程序进行备份也不下于十几次了,大部分都正常成功, 但也不乏出现这种情况的,小弟之前一般遇到这种问题, 都是直接忽略,换其他办法来进行备份,但是用惯了帝国备份王,换其他的方法备份数据,总感觉难

《深入理解计算机系统》 优化程序性能的几个方法

本文几个优化程序性能的方法出自CSAPP第五章,通过不断修改源代码,试图欺骗编译器产生有效的代码 我们先引入度量标准每元素的周期数(CPE),表示程序性能. 我们先定义一个数据结构   data_t 代表数据类型 1 typedef struct{ 2 long len; 3 data_t *data; 4 }vec_rec,*vec_prt; 以及常数IDENT和OP以便在后续的代码中进行不同的操作 //对所有向量的元素求和 #define IDENT 0 #define OP + //对所有

BizTalk开发系列(三十二)浅谈BizTalk主机性能优化

很多BizTalk的项目都要考虑到性能优化的问题,虽然BizTalk采用多线程处理消息的,大大提高了程序效率.但默认情况下 BizTalk的主机有很多阻止参数会控制BizTalk对服务器的资源使用率,从而约束了BizTalk的效率.之前做了一个200万条CSV数据通过 BizTalk传到数据库的程序.在不改变程序的情况下对主机性能做了一下简单优化,处理效率发生了成倍的增长. 程序逻辑 先简单的介绍一下程序的处理逻辑,CSV原文件大概有200多万条数据,文件大小50多M.每条只有两个字段总长度大概

优化程序性能(CSAPP:5)

[前言]虽然现在没有接触过大型项目,但是工作了会注重性能.学习一下,应该能更好更快的理解别人写的经典优秀的代码.结合CSAPP和自己的理解,总结一下. 一.程序优化综述 1.高效程序的特点 (1)适当的算法和数据结构.方法和数据的组织形式无疑是最关键的,是优化的基础: (2)代码能够被编译器转化成高效的可执行代码.需要深入了解使用的编译器的优化方法,和常见的优化策略: (3)运用现代并行编程技术.多核以及硬件支持提供更大的加速可能,例如GPU: 2.优化程序的一般步骤 (1)消除不必要的工作,例

近期业务需要所引发的性能优化问题,浅谈线程池性能优化

线程池对于性能优化无处不在 1.楼主在平时产品开发过程中所遇到的性能问题,特别是最近特别流行的微服务架构. web - java - 底层数据源(python亦或者opensatck),对于这种前后台分离的场景 无时无刻会存在对于业务场景需要对同一数据源进行百次,千次的重复调用过程. 性能方面就会出现接口延迟,过慢,超时等情况 下面就楼主最近遇到的一个业务场景加以举例说明:做云计算相关的想必都是知道,我们在为客户提供单板的过程中(也就是物理机):会对众多的单板进行管理,这里我们就引进主机组: 主