今天,我将告诉您什么是定点,为什么需要定点以及如何使用定点。
当由于浮点计算的特殊性而导致应用程序的性能明显下降时,就会出现这样的问题。 通常,对CPU进行锐化以进行整数运算,并且其中的FPU(浮点单元)协处理器的工作速度要慢一个数量级。 在这样的平台上根本没有FPU,用数字模拟操作会花费很多时间。 例如,在存在FPU的情况下,仅通过一个fmul命令执行浮点数的乘法,而在没有FPU的情况下,通过__mulsf3仿真功能进行乘法。 与fmul命令相比,__mulsf3函数以浮点数模拟操作,而计算以整数形式执行,这会导致机器代码和执行时间增加,而fmul命令将使用硬件快速执行此操作。资金。
这个问题有一个解决方案,它允许对整数类型的不动点进行计算。
这种类型的原理是将数字固定移位N位,其结果是小数可以表示为整数,并且该点之后的精度为2 ^N。 将浮点数转换为8位(2 ^ 8 = 1024)数量级的定点数的示例。
这是将浮点数转换为定点数的示例:
Fixed(12345,6789) = 1024 * 12345,6789 = 12641975,<s>1936</s>
小数点后的数字精度为2 ^ 8。
将定点数反向转换为浮点数的示例。
Float(12641975) = 12641975 / 1024 = 12345,678<s>7109375</s>
在这种情况下,反向翻译后的数字的格式为12345.6787109375,并且在句点之后为3位数字,最大精度实际上为2 ^ 8 = 1024。
定点类型的计算如何发生?
求和与差运算等同于普通整数运算。
Fixed(x) + Fixed(y) Fixed(x) - Fixed(y)
,以任何顺序
(1024 * x) + (1024 * y) (1024 * x) - (1024 * y)
这样的数字相乘就是这种形式。
(Fixed(x) * Fixed(y)) / p
,等效,为8位
((1024 * x) * (1024 * y)) / 1024
师
(Fixed(x) * p) / Fixed(y)
,也以8位的阶数表示
(1024 * 1024 * x)*(1024 * y)
溢流
在执行乘法和除法运算时,可能会发生溢出,从而导致错误的结果。 例如,如果使用32位整数类型,就会发生这种情况,并且在计算过程中会发生这种类型的溢出,并且由于这种溢出,该数字将丢失最高有效位。 有两种消除溢出的方法:
- 以64位整数类型执行计算。
- 以“反汇编”形式执行计算,例如,在乘以(xi + xf)*(yi + yf)= xi * yi + xf * yf + xi * yf + yi * xf时,前缀i和f表示整个部分以及后面的部分点。
用于在C ++中使用定点的类
#define DIGITS 1024 // #define EPS 20 // using namespace std; typedef signed int __int32_t; class Fixed { signed int x; Fixed(signed int a){ x = a; } public: Fixed(){ x = 0; } static Fixed fromInt(signed int val){ return Fixed(val*DIGITS); } static Fixed fromFloat(float val){ return Fixed((signed int)(val*DIGITS)); } float fixed2float(){ return ((float)x)/DIGITS; } Fixed sum(Fixed a,Fixed b){ return Fixed(a.x+bx); } Fixed diff(Fixed a,Fixed b){ return Fixed(ax-bx); } Fixed mul(Fixed a,Fixed b){ signed int c=ax*bx; if(c/bx != ax){ // Overflow! signed int i1 = ax/DIGITS; signed int i2 = bx/DIGITS; signed int f1 = (ax&(DIGITS-1)); signed int f2 = (bx&(DIGITS-1)); return Fixed((i1*i2)*DIGITS+(f1*f2)/DIGITS+i1*f2+i2*f1); }else{ return Fixed(c/DIGITS); } } Fixed div(Fixed a,Fixed b){ if(ax>(1<<21)){ // Overflow! signed int i = ax/DIGITS; signed int f = (ax&(DIGITS-1)); return Fixed(((i*DIGITS)/bx)*DIGITS+(f*DIGITS)/bx); }else{ return Fixed((ax*DIGITS)/bx); } } Fixed sqrt(Fixed k){ Fixed tmp(0); tmp.x = kx/2; signed int min = 0; signed int max = kx; Fixed quick(0); do{ tmp.x = (min+max)/2; quick = Fixed::mul(tmp,tmp); if(abs(quick.xk.x)<EPS) return Fixed(tmp); if(quick.x>kx){ max = tmp.x; }else{ min = tmp.x; } }while(true); } };