2013-07-10 20:13:03
【编程珠玑】读书笔记 时空开销模型
分析算法的好坏,一般从两个角度进行,时间复杂度与空间复杂度,通过理论的分析,可以得到这两个参数,但能不能得到实际代码具体的运行呢?
书中给出了空间、时间开销模型,用于分析代码的空间、时间开销,可以解决这个问题。下面给出具体的时空开销模型代码。
空间开销模型
模型写的很好,直接拿过来,完整代码见下方。
运行结果可能依系统而不同,此处给出我的环境:win7 32 位机+VS2010。
注意代码中的斜杠为续行符。
完整代码:
1 /* Copyright (C) 1999 Lucent Technologies */ 2 /* From 'Programming Pearls' by Jon Bentley */ 3 4 /* spacemod.cpp -- simple model for C++ space */ 5 6 #include <iostream> 7 using namespace std; 8 9 #define MEASURE(T, text) 10 { 11 cout << text << " "; 12 cout << sizeof(T) << " "; 13 int lastp = 0; 14 for (int i = 0; i < 11; i++) 15 { 16 T *p = new T; 17 int thisp = (int) p; 18 if (lastp != 0) 19 cout << " " << thisp - lastp; 20 lastp = thisp; 21 } 22 cout << " "; 23 } 24 25 // Must use macros; templates give funny answers 26 27 template <class T> 28 void measure(char *text) 29 { 30 cout << " measure: " << text << " "; 31 cout << sizeof(T) << " "; 32 } 33 34 struct structc { char c; }; 35 struct structic { int i; char c; }; 36 struct structip { int i; structip *p; }; 37 struct structdc { double d; char c; }; 38 struct structcd { char c; double d; }; 39 struct structcdc { char c1; double d; char c2; }; 40 struct structiii { int i1; int i2; int i3; }; 41 struct structiic { int i1; int i2; char c; }; 42 struct structc12 { char c[12]; }; 43 struct structc13 { char c[13]; }; 44 struct structc28 { char c[28]; }; 45 struct structc29 { char c[29]; }; 46 struct structc44 { char c[44]; }; 47 struct structc45 { char c[45]; }; 48 struct structc60 { char c[60]; }; 49 struct structc61 { char c[61]; }; 50 51 int main() 52 { 53 cout << "Raw sizeof"; 54 cout << " sizeof(char)=" << sizeof(char); 55 cout << " sizeof(short)=" << sizeof(short); 56 cout << " sizeof(int)=" << sizeof(int); 57 cout << " sizeof(float)=" << sizeof(float); 58 cout << " sizeof(struct *)=" << sizeof(structc *); 59 cout << " sizeof(long)=" << sizeof(long); 60 cout << " sizeof(double)=" << sizeof(double); 61 62 cout << " MEASURE macro "; 63 64 MEASURE(int, "int"); 65 MEASURE(structc, "structc"); 66 MEASURE(structic, "structic"); 67 MEASURE(structip, "structip"); 68 MEASURE(structdc, "structdc"); 69 MEASURE(structcd, "structcd"); 70 MEASURE(structcdc, "structcdc"); 71 MEASURE(structiii, "structiii"); 72 MEASURE(structiic, "structiic"); 73 MEASURE(structc12, "structc12"); 74 MEASURE(structc13, "structc13"); 75 MEASURE(structc28, "structc28"); 76 MEASURE(structc29, "structc29"); 77 MEASURE(structc44, "structc44"); 78 MEASURE(structc45, "structc45"); 79 MEASURE(structc60, "structc60"); 80 MEASURE(structc61, "structc61"); 81 82 cout << " measure template (strange results) "; 83 // Uncomment below lines to see answers change 84 measure<int>("int"); 85 measure<structc>("structc"); 86 measure<structic>("structic"); 87 88 return 0; 89 }
在我的机子上,运行结果如下:
(可以看到,该运行结果与书中给出的结果不同,但是同样反映了一个问题,就是用new运算符分配空间时,会有较大的额外开销,对下面的测试该开销在40字节左右)
Raw sizeof sizeof(char)=1 sizeof(short)=2 sizeof(int)=4 sizeof(float)=4 sizeof(struct *)=4 sizeof(long)=4 sizeof(double)=8 MEASURE macro int 4 48 96 48 48 48 48 48 48 48 48 structc 1 48 48 48 48 48 48 48 48 48 48 structic 8 56 56 56 19312 56 80 56 56 56 56 structip 8 56 56 56 56 56 56 56 56 56 56 structdc 16 64 64 64 64 88 64 64 64 64 64 structcd 16 64 64 64 64 64 64 64 64 64 64 structcdc 24 72 72 72 72 72 72 72 72 72 72 structiii 12 56 56 56 56 56 56 56 56 56 56 structiic 12 56 56 56 56 56 56 56 56 4504 56 structc12 12 56 56 56 56 56 56 56 56 56 56 structc13 13 64 64 64 64 64 64 64 64 64 64 structc28 28 72 72 72 72 72 72 72 72 72 72 structc29 29 80 80 80 80 80 80 80 104 80 80 structc44 44 88 88 88 88 88 88 88 88 88 88 structc45 45 96 96 96 96 96 96 96 96 96 96 structc60 60 104 104 104 104 104 104 104 104 104 104 structc61 61 112 112 112 112 112 112 112 112 112 112 measure template (strange results) measure: int 4 measure: structc 1 measure: structic 8 请按任意键继续. . .
时间开销模型
通过clock()函数进行计时,测试每个操作的平均时间,clock(),关于该函数的详细介绍,参见:http://www.cnblogs.com/youngforever/articles/3182876.html
用宏定义而不用模板的原因:???
完整代码:
1 /* Copyright (C) 1999 Lucent Technologies */ 2 /* From 'Programming Pearls' by Jon Bentley */ 3 4 /* timemod.c -- Produce table of C run time costs */ 5 6 #include <stdio.h> 7 #include <time.h> 8 #include <stdlib.h> 9 #include <math.h> 10 11 #define MAXN 100000 12 13 int x[MAXN]; 14 int startn = 5000; 15 int n; 16 17 /* FUNCTIONS TO BE TIMED */ 18 19 int intcmp(int *i, int *j) 20 { 21 return *i - *j; 22 } 23 24 #define swapmac(i, j) { t = x[i]; x[i] = x[j]; x[j] = t; } 25 26 void swapfunc(int i, int j) 27 { 28 int t = x[i]; 29 x[i] = x[j]; 30 x[j] = t; 31 } 32 33 #define maxmac(a, b) ((a) > (b) ? (a) : (b)) 34 35 int maxfunc(int a, int b) 36 { 37 return a > b ? a : b; 38 } 39 40 41 /* WORKHORSE */ 42 43 #define T(s) printf("%s (n=%d) ", s, n); 44 45 #define TRIALS 5 46 47 //必须加续行符,因为是宏定义而不是语句 48 49 #define M(op) { 50 printf(" %-22s", #op); 51 k = 0; 52 timesum = 0; 53 for (ex = 0; ex < TRIALS; ex++) 54 { 55 start = clock(); 56 for (i = 1; i <= n; i++) 57 { 58 fi = (float) i; 59 for (j = 1; j <= n; j++) 60 { 61 op; 62 } 63 } 64 t = clock()-start; 65 printf("%6d", t); 66 timesum += t; 67 } 68 nans = 1e9 * timesum / ((double) 69 n*n * TRIALS * CLOCKS_PER_SEC); 70 printf("%8.0f ", nans); 71 } //此处大括号后面加不加分号都可以,因为主函数在使用该宏时如M(k++); 已经加了分号,再加一个分号,只是会当做多了一个空语句而已 72 73 int main() 74 { 75 int i, j, k; 76 float fi, fj, fk; 77 int t, ex, timesum, start, globalstart; 78 double nans; 79 80 globalstart = clock(); 81 82 for (i = 0; i < n; i++) //此处n并没有初始化,就使用,不会出错吗?n为全局变量,在C++中会初始化为0,所以此时n为0 83 x[i] = rand(); 84 85 n = startn; 86 87 printf("C Time Cost Model, n=%d ", n); 88 89 T("Integer Arithmetic"); 90 M({}); 91 M(k++); 92 M(k = i + j); 93 M(k = i - j); 94 M(k = i * j); 95 M(k = i / j); 96 M(k = i % j); 97 M(k = i & j); 98 M(k = i | j); 99 100 T("Floating Point Arithmetic"); 101 M(fj=j;); 102 M(fj=j; fk = fi + fj;); 103 M(fj=j; fk = fi - fj;); 104 M(fj=j; fk = fi * fj;); 105 M(fj=j; fk = fi / fj;); 106 107 T("Array Operations"); 108 M(k = i + j); 109 M(k = x[i] + j); 110 M(k = i + x[j]); 111 M(k = x[i] + x[j]); 112 113 T("Comparisons"); 114 M(if (i < j) k++); 115 M(if (x[i] < x[j]) k++); 116 117 T("Array Comparisons and Swaps"); 118 M(k = (x[i]<x[k]) ? -1:1); 119 M(k = intcmp(x+i, x+j)); 120 M(swapmac(i, j)); 121 M(swapfunc(i, j)); 122 123 T("Max Function, Macro and Inline"); 124 M(k = (i > j) ? i : j); 125 M(k = maxmac(i, j)); 126 M(k = maxfunc(i, j)); 127 n = startn / 5; 128 129 T("Math Functions"); 130 M(fk = j+fi;); 131 M(k = rand();); 132 M(fk = sqrt(j+fi)); 133 M(fk = sin(j+fi)); 134 M(fk = sinh(j+fi)); 135 M(fk = asin(j+fi)); 136 M(fk = cos(j+fi)); 137 M(fk = tan(j+fi)); 138 139 n = startn / 10; 140 T("Memory Allocation"); 141 142 M(free(malloc(16));); 143 M(free(malloc(100));); 144 M(free(malloc(2000));); 145 146 /* Possible additions: input, output, malloc */ 147 printf(" Secs: %4.2f ", 148 ((double) clock()-globalstart) 149 / CLOCKS_PER_SEC); 150 151 return 0; 152 }
对每一种运算都利用宏定义 M(op),进行了TRIALS次测试,每次测试包含n*n次op操作,在M(op)中打印出了每次TRAIL的运行时间(下面运行结果中的2~6列),在最后给出了op操作每次执行的平均时间(下面运行结果中的最后一列)。
运行结果:
C Time Cost Model, n=5000 Integer Arithmetic (n=5000) {} 204 217 228 180 174 8 k++ 127 126 127 127 121 5 k = i + j 139 138 132 137 135 5 k = i - j 144 133 259 149 145 7 k = i * j 183 162 143 149 138 6 k = i / j 204 210 207 205 197 8 k = i % j 221 199 189 191 191 8 k = i & j 131 118 112 112 112 5 k = i | j 140 138 125 117 113 5 Floating Point Arithmetic (n=5000) fj=j; 123 121 117 118 120 5 fj=j; fk = fi + fj; 151 167 153 162 149 6 fj=j; fk = fi - fj; 155 168 171 160 165 7 fj=j; fk = fi * fj; 158 159 168 166 156 6 fj=j; fk = fi / fj; 352 356 354 354 355 14 Array Operations (n=5000) k = i + j 114 119 115 132 113 5 k = x[i] + j 132 138 141 139 119 5 k = i + x[j] 128 125 129 127 124 5 k = x[i] + x[j] 145 156 145 137 145 6 Comparisons (n=5000) if (i < j) k++ 100 112 121 122 129 5 if (x[i] < x[j]) k++ 149 161 140 144 147 6 Array Comparisons and Swaps (n=5000) k = (x[i]<x[k]) ? -1:1 192 197 197 191 200 8 k = intcmp(x+i, x+j) 1245 987 896 814 766 38 swapmac(i, j) 122 123 125 123 121 5 swapfunc(i, j) 808 798 795 797 798 32 Max Function, Macro and Inline (n=5000) k = (i > j) ? i : j 90 89 90 93 90 4 k = maxmac(i, j) 90 91 90 95 90 4 k = maxfunc(i, j) 772 774 779 777 771 31 Math Functions (n=1000) fk = j+fi; 3 2 2 3 3 3 k = rand(); 32 36 32 32 32 33 fk = sqrt(j+fi) 80 72 72 72 71 73 fk = sin(j+fi) 89 89 89 89 89 89 fk = sinh(j+fi) 489 485 488 486 494 488 fk = asin(j+fi) 130 133 139 137 137 135 fk = cos(j+fi) 100 91 94 89 89 93 fk = tan(j+fi) 102 100 106 98 99 101 Memory Allocation (n=500) free(malloc(16)); 144 139 139 142 162 581 free(malloc(100)); 189 143 172 142 158 643 free(malloc(2000)); 165 178 168 175 163 679 Secs: 38.56 请按任意键继续. . .