|
《Windows游戏编程大师技巧》(第二版)第11章(14) product=(n<<7) + (n<<9); // n*128 + n*512 = n*640 不过,如果处理器在1至2个时钟周期内就可以完成乘法运算,这种优化就失去意义了。 如果你的算法中应用到矩阵操作,要充分利用矩阵的稀疏性——一些元素为零。 在创建常量时,确保其为恰当的类型以防编译器编译出错或将其强迫转换为整数类型。最好是使用C++中新的const指示字。例如: const float f=12.45; 避免使用平方根、三角函数或任何复杂的数学函数。一般而言,这些复杂函数的计算都可以根据特定的假设或近似而找到一个简单的方法来实现。但即使结果还是不理想,你仍然可以做一张查找表。我在后面将会提及该表。 如果你要将一个大的浮点数组清零,要按如下方式使用memset(): memset((void *)float_array,0,sizeof(float)*num_floats); 然而事实上也只有这种情况下才能这样做,因为浮点数是以IEEE格式编码的,故而只有整数零和浮点零的数值才完全相等。 在执行数学运算时,看一看在编码前能否手工先将表达式简化。比如,n*(f+1)/n等于(f+1),因为除法和乘法的运算结果将n 消去了。 如果你要执行复杂的数学计算,而且你在下面的代码中需要再次用到计算结果,那么就将其暂存在高速缓存中。如下所示: // compute term that is used in more than one eXPression float n_squared = n*n; // use term in two different expressions pitch = 34.5*n_squared+100*rate; magnitude = n_squared / length; 最后,很重要的一点是确保将编译器的选项设定为打开浮点协处理器,这样编译出的代码的执行速度较快。 定点运算 几年以前,大多数3D引擎都采用定点运算来进行3D中大量的变换和数学运算。这是因为处理器对浮点的支持没有对整数的支持快,甚至在奔腾处理器上也是如此。但是今天,奔腾Ⅱ、Ⅲ和Katmai处理器拥有更好的浮点能力,所以定点运算不再那么重要。 然而在许多情况下,由浮点到整数的光栅变换仍然很慢,因此在内部循环的加法和减法运算中使用定点运算仍是一个较好的选择。在低档的奔腾机器上,这类运算依然比浮点运算要快,因此你可以运用技巧快速地从定点数中提取出整数部分,而不必进行float到int的类型转换。 无论如何,这些都具有一定的不确定性。今天,使用浮点来处理任何运算通常都是最好的选择,但是多了解一些定点运算总还是有帮助的。我的观点是使用浮点来处理所有的数据表示和变换,对于低水平的光栅变换可以分别试一试定点运算和浮点运算,看一看那种处理方法最快。当然,如果你使用纯硬件加速,无需多虑,只要一直使用浮点数即可。 记住了这些,下面让我们来看看如何表示定点数。 定点数的表示 所有的定点数学实际上是以整数尺度为基础的。比如,我们想用一个整数来表示10.5。这做不到,因为没有小数位。你可以将其截断为10.0或将其舍入为11.0,但10.5不是一个整数。但如果你将10.5放大10倍,10.5就变成了105.0,这是一个整数。这便是定点数的基础。你可以采用某一比例系数来对数值进行缩放,并在进行数学计算时将比例系数考虑进去。 由于计算机是二进制的,大部分游戏程序倾向于使用32位整数(或int),以16.16的格式来表示定点数。如图11-12所示。 图11-12:一种16.16定点数表示法 你可以将整数部分放在高16位,小数部分置于低16位。这样你已将整个数值放大为原来的216即65536倍。另外,为提取出一个定点数的整数部分,你可以移位并屏蔽掉高16位;为得到小数部分,你可以移位并屏蔽掉低16位。 以下是一些常用的定点数的类型: #define FP_SHIFT 16 // shifts to produce a fixed-point number #define FP_SCALE 65536 // scaling factor typedef int FIXPOINT; 在定点与浮点之间转换
|