Skip to content

Commit

Permalink
/编程思想/《代码大全2》-读书笔记,26.6 用低级语言重写代码
Browse files Browse the repository at this point in the history
  • Loading branch information
Ashiamd committed Sep 26, 2024
1 parent a0ea480 commit e6ca629
Showing 1 changed file with 327 additions and 0 deletions.
327 changes: 327 additions & 0 deletions docs/study/编程思想/《代码大全2》-读书笔记.md
Original file line number Diff line number Diff line change
Expand Up @@ -568,11 +568,338 @@

## 17.2 递归

除非只能用递归实现,不然通常建议使用迭代替代递归

## 17.3 goto

通常不建议使用goto,除非只能用goto完成某些功能

## 17.4 针对不常见控制结构的观点

# 第18章 表驱动法

## 18.1 表驱动法使用总则

常见的查表方法:

1. 直接访问
2. 索引访问
3. 阶梯访问

## 18.2 直接访问表

## 18.3 索引访问表

## 18.4 阶梯访问表

## 18.5 表查询的其他示例

# 第19章 一般控制问题

## * 19.1 布尔表达式

用狄摩根定理简化否认的布尔判断

| 原表达式 | 等价表达式 |
| --------------- | --------------------- |
| not A and not B | not (A and B) |
| not A and B | not (A or not B) |
| A and not B | not (not A or B) |
| A and B | not (not A or not B) |
| not A or not B | not (A and B) |
| not A or B | not (A and not B) |
| A ot not B | not( not A and B) |
| A or B | not (not A and not B) |

## 19.2 复合语句

## 19.3 空语句

## 19.4 驯服危险的深层嵌套

## 19.5 编程基础: 结构化编程

## 19.6 控制结构与复杂度

# 第5部分 代码改善

# 第20章 软件质量概述

## 20.1 软件质量的特性

## 20.2 改善软件质量的技术

## 20.3 不同质量保障技术的相对性能

## 20.4 什么时候进行质量保证工作

## 20.5 软件质量的普遍原理

# 第21章 协同构建

## 21.1 协同开发实践概要

## 21.2 结对编程

## 21.3 正式检查

## 21.4 其他类型的协同开发实践

# 第22章 开发者测试

+ 单元测试(Unittesting)是将一个程序员或者一个开发团队所编写的,一个完整的类、子程序或者小程序,从完整的系统中隔离出来进行测试。
+ 组件测试(Component testing)是将一个类、包、小程序或者其他程序元素,从一个更加完整的系统中隔离出来进行测试,这些被测代码涉及到多个程序 员或者多个团队。
+ 集成测试(Integration testing)是对两个或更多的类、包、组件或者子系统 进行的联合测试,这些组件由多个程序员或者开发团队所创建。这种测试通 常在有了两个可以进行测试的类的时候就应该尽快开始,并且一直持续到整 个系统开发完成。
+ 回归测试(Regression testing)是指重复执行以前的测试用例,以便在原先通过了相同测试集合的软件中查找缺陷。
+ 系统测试(System testing)是在最终的配置下(包括同其他软硬件系统的集 成)运行整个软件。以便测试安全、性能、资源消耗、时序方面的问题,以 及其他无法在低级集成上测试的问题。

## 22.1 开发者测试在软件质量中的角色

## 22.2 开发者测试的推荐方法

1. 对每一项相关的需求进行测试,以确保需要都已经被实现
2. 对每一个相关的设计关注点进行测试,以确保设计已经被实现
3. 用基础测试来扩充对需求和设计的详细测试用例
4. 使用一个检查表,其中记录着你在本项目迄今为止所犯的,以及过去的项目中所犯的错误类型

## 22.3 测试技巧锦囊

## 22.4 典型错误

## 22.5 测试支持工具

## 22.6 改善测试过程

## 22.7 保留测试记录

# 第23章 调试

## 23.1 调试概述

## 23.2 寻找缺陷

## 23.3 修正缺陷

## 23.4 调试中的心理因素

## 23.5 调试工具——明显的和不那么明显的

# 第24章 重构

## 24.1 软件演化的类型

## 24.2 重构简介

## * 24.3 特定的重构

+ 数据级的重构
1. 用具名变量代替神秘数值
2. 使变量的名字更为清晰且传递更多信息
3. 将表达式内联化
4. 用函数来代替表达式
5. 引入中间变量
6. 用多个单一用途变量代替某个多用途变量
7. 在局部用途中使用局部变量而不是参数
8. 将基础数据类型转化为类
9. 将一组类型码(type codes)转化为类或枚举类型
10. 将一组类型码转化为一个基类及其相应派生类
11. 将数组转化为对象
12. 把群集(collection)封装球来
13. 用数据类来代替传统记录
+ 语句级的重构
1. 分解布尔表达式
2. 将复杂布尔表达式转换成命名准确的布尔函数
3. 合并条件语句不同部分中的重复代码片段
4. 使用break或return而不是循环控制变量
5. 在嵌套的if-then-else语句一旦知道答案就立即返回,而不是去赋一个返回值
6. 用多态来替代条件语句(尤其是重复的case语句)
7. 创建和使用null对象而不是去检测空值
+ 子程序级重构
1. 提取子程序或者方法
2. 将子程序的代码内联化
3. 将冗长的子程序转化为类
4. 用简单算法替代复杂算法
5. 增加参数
6. 删除删除
7. 将查询操作从修改操作中独立出来
8. 合并相似的子程序,通过参数区分它们的功能
9. 将行为取决于参数的子程序拆分开来
10. 传递整个对象而非特定成员
11. 传递特定成员而非整个对象
12. 包装向下转型的操作
+ 类实现的重构
1. 将值对象转化为引用对象
2. 将引用对象转化为值对象
3. 用数据初始化替代虚函数
4. 改变成员函数或成员数据的位置
5. 将特殊代码提取为派生类
6. 将相似的代码结合起来放置到基类中
+ 类接口的重构
1. 将成员函数放到另一个类中
2. 将一个类变成两个
3. 删除类
4. 去除委托关系
5. 去掉中间人
6. 用委托代替继承
7. 用继承代替委托
8. 引入外部的成员函数
9. 引入扩展类
10. 对暴露在外的成员变量进行封装
11. 对于不能修改的类成员,删除相关的Set()成员函数
12. 隐藏那些不会在类之外被用到的成员函数
13. 封装不使用的成员函数
14. 合并那些非常类似的基类和派生类
+ 系统级重构
1. 为无法控制的数据创建明确的索引源
2. 将单向的类联系改为双向的类联系
3. 将双向的类联系改为单向的类联系
4. 用Factory Method模式而不是简单地构造函数
5. 用异常取代错误处理代码,或者做相反方向的变换

## 24.4 安全的重构

## 24.5 重构策略

# 第25章 代码调整策略

## 25.1 性能概述

## 25.2 代码调整简介

## 25.3 蜜糖和哥斯拉

## 25.4 性能测量

## 25.5 反复调整

## 25.6 代码调整方法总结

# 第26章 代码调整技术

## * 26.1 逻辑

+ 在知道答案后停止判断
1. 如果语言支持,可以利用逻辑与(&&)的短路特性实现提前结束if判断
2. for循环可以考虑几种可能的优化方案
1. 在达到可结束循环的条件后,提前break结束循环
2. 如果语言不支持break,则考虑通过goto跳转提前结束循环
3. for改成while
4. for改成while,数组最后一项之后的第一个空位置设置一个哨兵值(sentinel value),然后简单地在while中检测负值。在循环结束后,看看首先发现的值是在原数组的范围内还是在哨兵位置。
+ 按照出现频率来调整判断顺序
1. switch-case语句可以考虑按照出现频次排列case(不同语言实现方式不同,java计算hash值再走case,所以调整case顺序并不会有提升)
2. if-else-then语句,把出现频次高的判断提前
+ 相似逻辑结构之间的性能比较
1. **不同语言在不同情况下,if-else-then语句和swith-case语句的执行耗时不同,可以根据实际尝试后选择耗时较短的实现**
+ 用查询表替代复杂表达式
1. 假设3布尔变量各种搭配组合求某个值,可以考虑该用多维数组维护3布尔变量搭配组合获取的不同值
+ 使用惰性求值
1. 仅当值真正需要被使用时,再进行计算,避免不必要的提前计算(java stream流即遇到终端操作时才会触发计算)

## * 26.2 循环

+ 将判断外提
1. for循环内的if-else可以尝试挪到外部判断,变成if内部一个for循环,else内部一个for循环
+ 合并
1. 对相同元素操作的多个for循环合并成一个for循环
+ 展开
1. 增加单次for循环内执行的逻辑量。比如for循环里做下一个元素的递增操作,可以改成每次做下两个元素的递增操作,最后for循环外单独对左后一个元素做判断(算是拿可读性换性能)
+ 尽可能减少在循环内部做的工作
1. 将循环内重复计算的值改成for循环之前计算(比如减少引用,指针跳转访问,之前提前声明好对应的指针对象)
+ **哨兵值**
1. **在任何使用线性查找的场合,你都可以使用哨兵法——从链表到数组**。需要注意的是必须仔细选择哨兵值,并小心地把它放到数据结构中去(比如举例遍历一维数组,可以额外申请空间放哨兵值,然后减少for循环判断的条件,改成for循环内只判断哨兵值,for循环外再判断是否遍历到额外空间才寻找到哨兵值,是的话说明原先数组就没有哨兵值,不满足条件)
+ **把最忙的循环放在最内层**
1. 双层或多层for循环,把循环次数较少的for放外面,可以减少for循环总次数(比如原本外层for100次,内层for5次,实际就是100+100x5=600次;如果改成外层for5次,内层for100次,则为5+5x100=505次)
+ **削减强度**
1. **用多次轻量级计算代替一次代价高昂的运算(比如多次加法替代一次乘法)**

## * 26.3 数据变换

+ 使用整型数而不是浮点数
1. 整型数的加法和乘法要比浮点数的相应运算快很多
+ 数组维度尽可能少
1. 如果能用一维数组替代二维数组,则考虑用一维数组
+ 尽可能减少数组引用
1. 如果访问的数组元素不变,可直接用局部变量存储数据元素,而不是每次通过引用读取数据
+ 使用辅助索引
+ 使用缓存机制

## * 26.4 表达式

+ 利用代数恒等式

1. 通过代数恒等式,用低代价的操作替代复杂操作(比如用not (a or b)有些情况比not a and not b效率高,能减少一次not运算)

+ 削弱运算强度

1. 用加法代替乘法
2. 用乘法代替幂乘
3. 利用三角恒等式代换等价的三角函数
4. 用long或int来代替long long整数(但请注意使用机器字长的整数和非机器字长整数所带来的差异)
5. 用定点数或整型数代替浮点数
6. 用单精度数代替双精度数
7. 用移位操作代替整数乘2或除2

+ **编译期初始化**

1. 一些常用的数学计算量,可以考虑用常量维护,避免计算耗时(比如log2,可以考虑直接用近似值常量维护)

+ 小心系统函数

1. 系统函数运行起来很慢,提供的精度常常也是根本不需要的(比如log函数只需要整型参数和整型喊回值,甚至可以直接用含有一堆if的函数直接返回int值,比老实通过浮点数计算再转整型要快很多)

+ 使用正确的常量类型

1. 尽量避免隐式数据转化,给变量赋值时使用正确的类型

+ 预先算出结果

1. 一些计算耗时的可列举值,可以考虑提前计算出结果以常量或缓存的形式维护(比如计算精度要求不高的情况,可以用税务速算表等形式计算大概的税额)

通过预先计算优化程序可以有如下几种形式:

1. 在程序执行之前算出结果,然后把结果写入常量,在编译时赋值;
2. 在程序执行之前计算结果,然后把它们硬编码在运行时使用的变量里;
3. 在程序执行之前计算结果,把结果存放在文件中,在运行时载入;
4. 在程序启动时一次性计算出全部结果,每当需要时去引用;
5. 尽可能在循环开始之前计算,最大限度地减少循环内部需要做的工作:
6. 在第一次需要结果时进行计算,然后将结果保存起来以备后用。

+ 删除公共子表达式

1. 如果发现莫个表达式老是在你面前出现,就把它赋给一个变量,然后在需要的地方引用该变量,而非重新计算这个表达式

## 26.5 子程序

+ 将子程序重写为内联(特定语言特定场景下需要经过测试才能确定是否是优化)

## 26.6 用低级语言重写代码

1. 用高级语言编写整个应用程序
2. 对程序进行完整的测试,验证其正确性
3. 如果测试后发现需要改进程序性能,就对程序进行分析,确定出热点
4. 把几小段代码在低级语言中重写,以此提高整体性能(实际开发中,一些业务场景比如文件操作,如果用shell更方便,可以考虑调用shell程序而不是用当前编程语言写一套冗长的文件操作程序;或者比如在C/C++中嵌入使用汇编语言)

## 26.7 变的越多, 事情反而越没变

# 第6部分 系统考虑

# 第27章 程序规模对构建的影响

## 27.1 交流和规模



## 27.2 项目规模的范围

## 27.3 项目规模对错误的影响

## 27.4 项目规模对生产率的影响

## 27.5 项目规模对开发活动的影响

# 第28章 管理构建

# 第29章 集成

# 第30章 编程工具

0 comments on commit e6ca629

Please sign in to comment.