无符号模数:替代方法?

Lir*_*una 31 c c++ math optimization

我需要优化这个非常微小但却令人讨厌的功能.

unsigned umod(int a, unsigned b)
{
    while(a < 0)
        a += b;

    return a % b;
}
Run Code Online (Sandbox Code Playgroud)

在你喊出"你不需要优化它"之前,请记住,这个函数被称为整个程序生命周期的50%,因为它被称为最小测试用例基准测试的21495808次.

该函数已由编译器内联,因此请不要添加inline关键字.

Tro*_*nic 14

这可以避免循环:

int tmp = a % b;
if (tmp < 0) tmp += b;
Run Code Online (Sandbox Code Playgroud)

请注意,a和b都需要签名.

  • `int tmp = a%b; return tmp + b*(tmp <0);`更快. (3认同)
  • 这与OP的原始结果不同.例如,使用"a = -10"和"b = 3",原始值为2但是得到0. (3认同)
  • `( - 10)%3U`不给-1. (2认同)
  • 更新版本`umod(-10,3)== 2`:`返回%(int)b + b*(a <0);`虽然这将失去b的一半范围. (2认同)
  • +1提及这将失去b的一半范围,这将违反声明b _unsigned_的目的. (2认同)

caf*_*caf 10

这应该这样做:

unsigned umod(int a, unsigned b)
{
    if (a < 0)
    {
        unsigned r = (-a % b);
        if (r)
            return b - r;
        else
            return 0;
    }
    else
        return a % b;
}
Run Code Online (Sandbox Code Playgroud)

测试匹配原始.限制是a > INT_MIN2s补充机器.


Joh*_*ooy 7

使用〜:)

unsigned umod(int a, unsigned b)
{
    if (a<0) return b-1-~a%b;
    return a%b;
}
Run Code Online (Sandbox Code Playgroud)

%优先级高于-

如果在-a是b的倍数时可以返回b而不是0,则可以保存一些操作

unsigned umod(int a, unsigned b)
{
    if (a<0) return b - (-a % b);
    return a%b;
}
Run Code Online (Sandbox Code Playgroud)

略微打高尔夫球版:)

unsigned umod(int a, unsigned b)
{
return(a<0)?b-(-a%b):a%b;
}
Run Code Online (Sandbox Code Playgroud)

这是生成的程序集

1    .globl umod3
2       .type   umod3, @function
3    umod3:
4    .LFB3:
5       .cfi_startproc
6       testl   %edi, %edi
7       js      .L18
8       movl    %edi, %eax
9       xorl    %edx, %edx
10      divl    %esi
11      movl    %edx, %eax
12      ret
13      .p2align 4,,10
14      .p2align 3
15   .L18:
16      movl    %edi, %eax
17      xorl    %edx, %edx
18      negl    %eax
19      divl    %esi
20      subl    %edx, %esi
21      movl    %esi, %edx
22      movl    %edx, %eax
23      ret
Run Code Online (Sandbox Code Playgroud)

  • 它确实如此,但我在讨论`ret`之前的最后两个助记符(第21行和第22行).这些行将最终结果从'%esi`移动到'%edx`,然后从'%edx`移动到`%eax` - 只需从`%esi`移动到'%eax`即可完成 (2认同)