ARM中用乘法代替除法的优化

ARM中用乘法代替除法的优化,第1张

  ARM在硬件上不支持除法指令,编译器是通过调用C库函数来实现除法运算的,有许多不同类型的除法程序来适应不同的除数和被除数。但直接利用C库函数中的标准整数除法程序,根据执行情况和输入 *** 作数的范围,要花费20~100个周期,消耗较多的软件运行时间。在实时嵌入式应用中,对时间参数较为敏感,故可以考虑如何优化避免除法消耗过多的CPU运行时间。

  除法和模运算(/和%)执行起来比较慢,所以应尽量避免使用。但是,除数是常数的除法运算和用同一个除数的重复除法,执行效率会比较高。在ARM中,可以利用单条MUL指令实现乘法 *** 作。本文将阐述如何用乘法运算代替除法运算,以及如何使除法的次数最少化。

  1 避免除法运算

  在非嵌入式领域,因为CPU运算速度快、存储器容量大,除法 *** 作通常都是不加考虑直接使用的。但在嵌入式领域,首先需要考虑的是这些除法 *** 作是否是必须的。以对环形缓冲区 *** 作为例,经常要用到除法,其实完全可以避免这些除法运算。

  

ARM中用乘法代替除法的优化,第2张

 

  假定有一个buffer_size大小的环形缓冲区,如图1所示,offset指定目前所在的位置。通过increment字节来增加offset的值,一般是这样写的:

  0ffset=(Offset+increment)%buffer_size;

  效率更高的写法是:

  offset+=increment;

  if(offset>=buffer_size){

  offset-=buffer_size;

  }

  第一种写法要花费50个周期,而第二种因为没有除法运算,只须花费3个周期。这里假定increment

  如果不能避免除法运算,那么就应尽量使除数和被除数是无符号的整数。有符号的除法程序执行起来更加慢,因为它们先要取得除数和被除数的绝对值,再调用无符号除法运算,最后再确定结果的符号。

  2 充分利用商和余数

  许多C语言库中的除法函数返回商和余数。换句话说,每一个除法运算,余数是可以无偿得到的,反之亦然。例如,要在屏幕缓冲区找到偏移量为offset的屏幕位置(x,y),可以这样写:

  typeclef struct{

  int x;

  int y;

  }point;

  point getxy_v1(unsigned int offset,unsigned int bytes_per_line){

  point p;

  p.y=offset/lt)ytes_per_line;

  p.x=offset - p.y* bytes_per_line;

  return p;

  }

  这里,似乎对p.x使用减法和乘法,少了一次除法运算;但是,实际上使用模运算或者取余 *** 作效率更高,对getxy_v1改进如下:

  point getxy_v2(unsigned int offset,unsigned int bytes_per_line){

  point P;

  P.x=offset%bytes_per_1ine;

  P.y=offset/bytes_per_line;

  return P;

  }

  从下面编译器的输出结果可以看到,只有一次除法调用。实际上,这个程序要比前面的getxy_vl少4条指令(注意,并不是对所有的编译器和C库都有这样的结果)。

  getxy_v2

  STMFD r13!,{r4,r14};保存r4,lr人堆栈

  MOV r4,r0 ;赋值后r4保存的为点P基址

  MOV r0,r2 ;r0=bytes_per_line

  BL rt_udiv ;调用无符号除法例程

  (r0.;r1)=(rl/r0,rl%r0)

  STR r0,[r4,#4] ;P.y=offset/bytes_per_line

  STR rl,[r4,#o] ;P.x=offset%bytes_per_line

  LDMFD r13!,(r4,pc);恢复上下文,返回

  

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/dianzi/2474377.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-08-04
下一篇 2022-08-04

发表评论

登录后才能评论

评论列表(0条)

保存