学编程是学java还是学python,初学者学java还是python
介绍
本应用笔记介绍了如何使用ARM C编译器和ARM或精简汇编来创建高效的算术代码。因为ARM的核心是整数处理器,所以所有的浮点运算都必须用整数运算来模拟。用定点算法代替浮点数,可以大大提高很多算法的性能。
本文件包含以下部分:
定点运算原理:描述定点运算所需的数学概念。
例如,给出了一个制作信号处理和图形处理定点代码的例子。这是两种最常见的用法。
c:涵盖了在c中实现定点代码的实际细节。示例程序提供了一组宏定义。
汇编程序:介绍一个汇编程序的例子。
定点算法原理
在计算数学中,一对整数(n,e)(尾数和指数)可以用来近似分数。这是一个整数,代表分数n2e。e可以认为N的位数必须移动到二进制小数点之前。例如
我是尾数(n)
这是博览会(e)
伯尼(Bernard的昵称)(m.)
最差的
01100100
-1
011001000.
200
01100100
0
01100100.
100
01100100
一个
0110010.0
50
01100100
2
011001.00
25
01100100
三
01100.100
12.5
01100100
七
0.1100100
0.78125
如果e是一个变量,保存在寄存器中,编译时未知,(n,e)称为浮点数。如果事先知道e,(n,e)称为编译时的固定点数。通过存储尾数,可以将定点存储在标准整数变量(或寄存器)中。
关于常数点,指数E通常用字母q表示,下面几节描述如何对两个常数进行基本的算术运算。两个算法是a=n2pa=n2p和b=m2qb=m2q,结果表示为c=k2rc=k2r。其中p、q和r是固定的常数指数。
计算时,只需对尾数n m进行两次计算即可得到k .其中它们的指数用于转换。存储实际数时,只存储尾数。索引由另一个相应的数字保存。
指数变化
对定点数执行的最简单的操作是改变索引。为了将索引从P变为R(执行操作c=a),可以通过简单的移位从N计算出随机数K。
因为n2p=n2rp2r n2p=n2rp2r
k=n=p(if ) r=p))))).
k=n(pr ) k=n ) pr ) if ) pr ) if(pr))
加法和减法
要运算c=a b,先把A和B变换成和C一样的指数R,然后把尾数相加。这个方法如下。
N2RM2R=(NM ) N2RM2R=(NM ) 2R
减法相似性
增加
乘积c=ab可以通过简单的整数乘法来实现。方程式如下。
ab=N2 pm 2 q=(nm)2))PQ)ab=N2 pm 2 q=(nm)2(PQ))))65
因此,乘积n * m是指数p q的答案的尾数。要将答案转换为指数r,请如上所述进行移位。例如
k=(nm))pQR)k=(nm))pQR)if)pq=r)if)pq=r)
分开
C=a/b也可以通过简单的整数除法来进行。公式如下。
a/b=(N2P)/M2Q))n/m)2qp=)n/m)2r qp2ra/b=(n2p)/M2Q))n/m)2r qp2r)
为了不损失精度,必须在除以m之前执行2r qp2r qp乘法。例如,
k=(n=p ) if ) rq=p).
平方根
平方根的公式如下。
a=N2P=N22RP2ra=N2P=N22RP2R
换句话说,isqr是整数的平方根函数(例如c=ac=a执行isqr(n2RP) k=isqr) n2RP)。
溢出
上式展示了只使用整数运算对定点数进行加、减、乘、除、开方等基本运算的方法。但是,为了在2r2r()表示的结果中准确存储答案,必须保证在计算过程中不会发生溢出。如果不仔细选择指数,每左移一次,加/减或乘就会溢出,成为无意义的答案。
下面这个“真实世界”的例子说明了如何选择一个指数。
例子
信号处理
在信号处理中,数据通常由-1和1之间的分数组成。
本例使用指数Q和32位整数尾数(这样每个值都可以保存在ARM寄存器中)。要能够将两个数相乘而不溢出,需要2q32或者q=15。实际上,通常选择q=14,因为它允许多次累加相乘,而没有溢出的风险。
在编译时固定q=14。那么0xFFFFC000代表-1,0x00004000代表1,0x00000001代表214214,最精确的除数。
假设x,y是两个q=14尾数,n,m是两个整数。通过应用上面的公式,您可以得到基本操作,其中a为正常的整数:
操作
产生q=14格式的答案尾数的代码
x y
x y
x a
x (a14)
辅助放大器(辅助放大器的缩写)
x*a
正常男性染色体组型
(x*y)14
x/a
x/a
a/b
(a14)/b
x/y
(x14)/y
xx
sqr(x14)
图像处理
在这个例子中,(x,y,z)坐标以八位小数信息(q=8)以小数形式存储。如果x存储在一个32位寄存器中,那么x的最低字节给出小数部分,最高的三部分是整数部分。
要计算距离原点的距离d,以q=8的形式:d=x2 y2 z2-d=x2 y2 z2
如果您直接应用上述公式并将所有中间答案以q=8的形式保存,则会得到以下代码:
x=(x*x)8平方x
y=(y*y)8平方y
z=(z*z)8平方z
s=x y z平方和
d=sqrt(S8)q=8形式的距离
一
2
3
四
5
或者,如果您将中间答案保持为q=16格式,则减少班次数并提高准确度:
q=16形式的x=x*x的平方
y=y * y q=16形式的y的平方
q=16形式的z=z*z的平方
s=x y x q=16形式的平方和
d=q=8形式的sqr(s)距离d
一
2
3
四
5
总结
如果你以q形式相加两个数字,它们将保持q型。
如果你用q形式乘以两个数字,答案是2q形式。
如果你采用q形式的数字的平方根,答案是q/2形式。
要从q型转换为r型,你需要向左移(r-q)或向右移(q-r),取决于q和r中哪一个更大
要获得最佳精度结果,请选择最大的问,并保证中间计算不能溢出。
C程序
可以使用标准整数算术运算在C中对定点算术进行编程,并且当需要时(通常在确保答案仍然是q形式之前或之后的操作之前或之后)使用移位来改变问-形式。
为了使编程更容易阅读,已经定义了一组C宏。下面的示例程序定义了这些宏并说明了它们的用法:
注:编译需要在末尾加上-lm选项,如(同groundcontrolcenter)地面控制中心固定值
/*一个简单的C程序,用来说明定点运算的用法*/
#包括
#包括
#包括
/*定义宏*/
/*对固定的两个数a和b执行的基本操作
点q格式返回q格式的答案*/
#定义FADD(a,b) ((a) (b))
#定义FSUB(a,b) ((a)-(b))
#定义FMUL(a,b,q) (((a)*(b))(q))
#定义FDIV(a,b,q)
/*基本运算,其中a是定点q格式,b是
整数*/
#定义FADDI(a,b,q) ((a) ((b)
#定义FSUBI(a,b,q)((a)-(b)
#定义FMULI(a,b) ((a)*(b))
#定义FDIVI(a,b) ((a)/(b))
/*将a从雌三醇环戊醚格式转换为q2格式*/
#定义FCONV(a,q1,q2) (((q2)(q1))?(a)((q1)-(q2)))
/* Q1格式的a和q2格式的b之间的一般操作
以q3格式返回结果*/
#定义FADDG(a,b,q1,q2,q3) (FCONV(a,q1,q3) FCONV(b,q2,q3))
#定义FSUBG(a,b,q1,q2,q3) (FCONV(a,q1,q3)-FCONV(b,q2,q3))
#定义FMULG(a,b,q1,q2,q3) FCONV((a)*(b),(q1) (q2),q3)
#定义FDIVG(a,b,q1,q2,q3) (FCONV(a,q1,(q2) (q3))/(b))
/*在浮点之间来回转换*/
#定义TOFIX(d,q) ((int)( (d)*(double)(1
#定义TOFLT(a,q) ( (double)(a)/(double)(1
#定义测试(修复、FLT、字符串){ \
a=a1=randint();\
b=bi=a2=randint();\
fa=TOFLT(a,q);\
fa1=TOFLT(a1,Q1);\
fa2=TOFLT(a2,Q2);\
fb=TOFLT(b,q);\
ans1=FIX\
ans 2=FLT;\
printf(测试%s\n定点答案=%f\n浮点答案=%f\n ,\
STR,TOFLT(ans1,q),ans 2);\
}
int randint(void) {
int I;
I=rand();
i=i 32767
if(rand()1)I=-I;
返回我;
}
int main(void) {
int q=14,q1=15,q2=7,q3=14
双fa、fb、fa1、fa2
int a,b,bi,a1,a2;
int ans1
双ans2
/*用一些随机数据测试每个宏*/
测试(FADD(a,b),fa fb,‘FADD’);
测试(FSUB(a,b),fa-fb, FSUB );
TEST(FMUL(a,b,q),fa*fb, FMUL );
TEST(FDIV(a,b,q),fa/fb, FDIV );
TEST(FADDI(a,bi,q),fa bi, FADDI );
TEST(FSUBI(a,BI,q),fa-bi, FSUBI );
TEST(FMULI(a,bi),fa*bi, f苏比);
TEST(FDIVI(a,bi),fa/bi, FSUBI );
TEST(FADDG(a1,a2,q1,q2,q3),fa1 fa2, FADDG );
TEST(FSUBG(a1,a2,q1,q2,q3),fa1-fa2, FSUBG );
TEST(FMULG(a1,a2,q1,q2,q3),fa1*fa2, FMULG );
TEST(FDIVG(a1,a2,q1,q2,q3),fa1/fa2, FDIVG );
printf(已完成标准测试\ n’);
/*下面的代码将通过对
系列(效率不高,但作为示例很有用)并进行比较
实际值*/
while (1) {
printf(请输入要 exp 的数字(1):);
scanf(%lf ,fa);
printf( x=%f\n ,fa);
printf( exp(x)=%f\n ,exp(fa));
q=14/*设置固定点*/
a=TOFIX(fa,q);/*获取定点格式的*/
a1=FCONV(1,0,q);/* a的0次方*/
a2=1;/* 0阶乘*/
ans 1=0;/*迄今为止的系列总和*/
for(bi=0;bi10bi ) { /*做十项级数*/
int j;
j=FDIVI(a1,a2);/* a^n/n!*/
ans1=FADD(ans1,j);
a1=FMUL(a1,a,q);/*将a的功率增加1 */
a2=a2 *(bi 1);/*下一阶乘*/
printf(Stage %d answer=%f\n ,bi,TOFLT(ans1,q));
}
}
返回0;
}
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。