Detail

记录一些有助于提高代码性能和平时一些难以想到的细节处理

Posted by 袁平 on August 24, 2018

前言

本文记录一些有助于提高代码性能和平时一些难以想到的细节处理

正文

一. 边界值

1.1 基本类型的范围限制

一般而言, 看到基本类型, 特别是返回值或者涉及到计算的, 都应该考虑基本类型的范围限制

  • 比如实现库函数: double Pow(double base, double exp)时, 需要考虑大数问题(如果要求是任意大的数字, 则需要使用特殊的数据结构来表示数据, 比如用字符串或者数组来表示大的数字, 以确保不会溢出(这也是大数问题的解决方法))

二. 性能

性能的影响一般分为时间性能和空间性能, 一般性能的提升考虑的方面有: 递归转循环, 位运算代替加减乘除, 算法改进(如: 利用全局有序或者局部有序使用二分等)

2.1 快速计算乘方

计算

  • 公式如下
  • 除了使用常规方法, 即一个n次循环计算乘方外, 可利用上面的公式来快速计算; 该公式是明显的递归式
double PowerWithUnsignedExponent(double base, unsigned int exponent) // 注意 
{
    if (0 == exponent) 
        return 1;
    if (1 == exponent) 
        return base;
    double result = PowerWithUnsignedExponent(base, exponent >> 1); // 注意
    result *= result;
    if (1 == exponent & 0x1) // 注意
        result *= base;
    return result;
} 
  • 上面的代码中需要注意的几点
    1. 使用unsigned来进一步限定范围
    2. 判等时, 常量放在左边
    3. 使用移位运算代替乘除
    4. 使用与运算代替奇数和偶数判断

2.2 位运算

2.2-1 奇偶判断

奇数二进制最后一位为1, 可利用与运算判断

if (1 == target & 0x1) 
{
    // 奇数...
}
else 
{
    // 偶数...
}

2.2-2 位移运算代替乘除

  • 左移<<一位, 相当于乘2; 右移>>一位, 相当于除以2
  • 注意移位规则
    1. 左移: 右边直接补充0
    2. 右移: 如果是一个无符号数, 左边用0填充n位; 如果是有符号数, 左边使用其符号位填充n位

三. 编码细节

记录一些常见或者很隐晦的编码错误或陋习

3.1 浮点数的相等判断

  • 不可直接使用a == b的形式判断, 因为计算机表示浮点数是无限循环小数, 但是float和double是有限的, 结果就会差那么一点点; 具体参见回答; 所以一般会将浮点数的判等转换为<=或者>=, 即如下重写一个equals()函数; 同时需要注意的是当用浮点常量和浮点变量相比较时, 不要忘了还是应该用这种比较噢
int equals(double a, double b) 
{
    return fabs(a - b) < exp;  // 其中exp为精度(如: 0.000001), 需要具体讨论得出
}