在C / C ++中是否有使用%(模数)的替代方法? [英] Is there any alternative to using % (modulus) in C/C++?

查看:154
本文介绍了在C / C ++中是否有使用%(模数)的替代方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我读过某个地方,模数运算符在小型嵌入式设备(如没有整数除法指令的8位微控制器)上效率不高。也许有人可以确认这一点,但是我认为差异比整数除法运算慢5-10倍。



除了保留计数器之外,还有另一种方法吗?变量和手动溢出到模拟点0?

  const int FIZZ = 6; (int x = 0; x< MAXCOUNT; x ++)
{
if(!(x%FIZZ))print(Fizz\\\
); //在某些系统上缓慢
}

vs:



我目前正在做的方式:

  const int FIZZ = 6; 
int fizzcount = 1; (int x = 1; x $ {
if(fizzcount> = FIZZ)
{
print(Fizz\ N);
fizzcount = 0;
}
}


解决方案

,按位运算的乐趣。许多分割程序的副作用是模数 - 因此在少数情况下,分割实际上要比模数更快。我有兴趣看到你收到这些信息的来源。具有乘法器的处理器使用乘法器有趣的分割程序,但是您可以通过另外两个步骤(乘法和减法)从分割结果到模数,因此它仍然可比。如果处理器有一个内置的划分程序,你可能会看到它也提供了剩余的。



尽管如此,还有一小部分数字理论致力于模块化算术,如果您真的想了解如何优化模数运算,则需要研究。例如,模块化的算术对于生成魔术方块非常方便。



所以,在这方面,这里是一个非常低级的外观在x的一个例子的模数的数学,应该显示你可以比较多少简单:






也许更好的方法来考虑问题是数字
基数和模算法。例如,您的目标是计算DOW
mod 7,其中DOW是
周的一天的16位表示。你可以写成:

  DOW = DOW_HI * 256 + DOW_LO 

DOW%7 =( DOW_HI * 256 + DOW_LO)%7
=((DOW_HI * 256)%7 +(DOW_LO%7))%7
=((DOW_HI%7 * 256%7)+(DOW_LO%7 ))%7
=((DOW_HI%7 * 4)+(DOW_LO%7))%7

以这种方式表示,您可以单独计算高字节和低字节的模7
结果。将结果乘以
4,并将其添加到低位,然后最终计算结果模7。



计算8位的mod 7结果,位数可以以
的方式执行。你可以这样写八进制数字:

  X = a * 64 + b * 8 + c 

其中a,b和c是3位数字。


$ b $(b%7)*(8%7)+ c%7)%7
=(a%7 + b%7 + c%7)%7
=(a + b + c)%7

64%7 = 8%7 = 1



当然,a,b和c是

  c = X& 7 
b =(X>> 3)& 7
a =(X>> 6)& 7 //(实际上,a只有2位)。

a + b + c 7 + 7 + 3 = 17 。所以,你需要
一个八进制的步骤。完整的(未经测试的)C版本可以是
,写成如下:

  unsigned char Mod7Byte(unsigned char X)
{
X =(X& 7)+((X> 3)& 7)+(X> 6);
X =(X& 7)+(X> 3);

返回X == 7? 0:X;
}

我花了一些时间写了一个PIC版本。实际实现
与上述略有不同

  Mod7Byte:
movwf temp1;
andlw 7; W = c
movwf temp2; temp2 = c
rlncf temp1,F;
swapf temp1,W; W = a * 8 + b
andlw 0x1F
addwf temp2,W; W = a * 8 + b + c
movwf temp2; temp2现在一个6位数
andlw 0x38;获得高3位== a'
xorwf temp2,F; temp2现在有3个低位== b'
rlncf WREG,F;将高位右移4
swapf WREG,F;
addwf temp2,W; W = a'+ b'

;在这一点上,W在0和10之间


addlw -7
bc Mod7Byte_L2
Mod7Byte_L1:
addlw 7
Mod7Byte_L2:
return

这是一个用于测试算法的liitle例程

  clrf x 
clrf count

TestLoop:
movf x,W
RCALL Mod7Byte
cpfseq count
bra fail

incf count,W
xorlw 7
skpz
xorlw 7
movwf count

incfsz x,F
bra TestLoop
已通过:

最后, 16位结果(我没有测试),你可以
写:

  uint16 Mod7Word(uint16 X )
{
return Mod7Byte(Mod7Byte(X& 0xff)+ Mod7Byte(X>> 8)* 4);
}

Scott





I read somewhere once that the modulus operator is inefficient on small embedded devices like 8 bit micro-controllers that do not have integer division instruction. Perhaps someone can confirm this but I thought the difference is 5-10 time slower than with an integer division operation.

Is there another way to do this other than keeping a counter variable and manually overflowing to 0 at the mod point?

const int FIZZ = 6;
for(int x = 0; x < MAXCOUNT; x++)
{
    if(!(x % FIZZ)) print("Fizz\n"); // slow on some systems
}

vs:

The way I am currently doing it:

const int FIZZ = 6;
int fizzcount = 1;
for(int x = 1; x < MAXCOUNT; x++)
{
    if(fizzcount >= FIZZ) 
    {
        print("Fizz\n");
        fizzcount = 0;
    }
}

解决方案

Ah, the joys of bitwise arithmetic. A side effect of many division routines is the modulus - so in few cases should division actually be faster than modulus. I'm interested to see the source you got this information from. Processors with multipliers have interesting division routines using the multiplier, but you can get from division result to modulus with just another two steps (multiply and subtract) so it's still comparable. If the processor has a built in division routine you'll likely see it also provides the remainder.

Still, there is a small branch of number theory devoted to Modular Arithmetic which requires study if you really want to understand how to optimize a modulus operation. Modular arithmatic, for instance, is very handy for generating magic squares.

So, in that vein, here's a very low level look at the math of modulus for an example of x, which should show you how simple it can be compared to division:


Maybe a better way to think about the problem is in terms of number bases and modulo arithmetic. For example, your goal is to compute DOW mod 7 where DOW is the 16-bit representation of the day of the week. You can write this as:

 DOW = DOW_HI*256 + DOW_LO

 DOW%7 = (DOW_HI*256 + DOW_LO) % 7
       = ((DOW_HI*256)%7  + (DOW_LO % 7)) %7
       = ((DOW_HI%7 * 256%7)  + (DOW_LO%7)) %7
       = ((DOW_HI%7 * 4)  + (DOW_LO%7)) %7

Expressed in this manner, you can separately compute the modulo 7 result for the high and low bytes. Multiply the result for the high by 4 and add it to the low and then finally compute result modulo 7.

Computing the mod 7 result of an 8-bit number can be performed in a similar fashion. You can write an 8-bit number in octal like so:

  X = a*64 + b*8 + c

Where a, b, and c are 3-bit numbers.

  X%7 = ((a%7)*(64%7) + (b%7)*(8%7) + c%7) % 7
      = (a%7 + b%7 + c%7) % 7
      = (a + b + c) % 7

since 64%7 = 8%7 = 1

Of course, a, b, and c are

  c = X & 7
  b = (X>>3) & 7
  a = (X>>6) & 7  // (actually, a is only 2-bits).

The largest possible value for a+b+c is 7+7+3 = 17. So, you'll need one more octal step. The complete (untested) C version could be written like:

unsigned char Mod7Byte(unsigned char X)
{
    X = (X&7) + ((X>>3)&7) + (X>>6);
    X = (X&7) + (X>>3);

    return X==7 ? 0 : X;
}

I spent a few moments writing a PIC version. The actual implementation is slightly different than described above

Mod7Byte:
       movwf        temp1        ;
       andlw        7        ;W=c
       movwf        temp2        ;temp2=c
       rlncf   temp1,F        ;
       swapf        temp1,W ;W= a*8+b
       andlw   0x1F
       addwf        temp2,W ;W= a*8+b+c
       movwf        temp2   ;temp2 is now a 6-bit number
       andlw   0x38    ;get the high 3 bits == a'
       xorwf        temp2,F ;temp2 now has the 3 low bits == b'
       rlncf   WREG,F  ;shift the high bits right 4
       swapf   WREG,F  ;
       addwf        temp2,W ;W = a' + b'

 ; at this point, W is between 0 and 10


       addlw        -7
       bc      Mod7Byte_L2
Mod7Byte_L1:
       addlw        7
Mod7Byte_L2:
       return

Here's a liitle routine to test the algorithm

       clrf    x
       clrf    count

TestLoop:
       movf        x,W
       RCALL   Mod7Byte
       cpfseq count
        bra    fail

       incf        count,W
       xorlw   7
       skpz
        xorlw        7
       movwf   count

       incfsz        x,F
       bra        TestLoop
passed:

Finally, for the 16-bit result (which I have not tested), you could write:

uint16 Mod7Word(uint16 X)
{
 return Mod7Byte(Mod7Byte(X & 0xff) + Mod7Byte(X>>8)*4);
}

Scott


这篇关于在C / C ++中是否有使用%(模数)的替代方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆