最好的方法来获得整数除法和余数

C++ Best way to get integer division and remainder

本文关键字:整数 除法 余数 方法      更新时间:2023-10-16

我只是想知道,如果我想用a除以b,并且对结果c和余数都感兴趣(例如,我有几秒,想把它分成分钟和秒),最好的方法是什么?

int c = (int)a / b;
int d = a % b;

int c = (int)a / b;
int d = a - b * c;

double tmp = a / b;
int c = (int)tmp;
int d = (int)(0.5+(tmp-c)*b);

也许有一个神奇的函数可以同时给出两者?

在x86上,余数是除法本身的副产品,所以任何半体面的编译器都应该能够使用它(而不是再次执行div)。这可能在其他体系结构中也可以实现。

指令:DIV src

注:无符号除法。将累加器(AX)除以"src"。如果除数是一个字节值,结果放在AL ,余数放在AH。如果除数是一个字值,那么DX:AX除以"src",结果被存储在AX 中,余数存储在DX中。

int c = (int)a / b;
int d = a % b; /* Likely uses the result of the division. */

std::div返回一个包含结果和余数的结构

至少在x86上,g++ 4.6.1只使用IDIVL,并从单个指令中获取两者。

c++代码:

void foo(int a, int b, int* c, int* d)
{
  *c = a / b;
  *d = a % b;
}
x86代码:

__Z3fooiiPiS_:
LFB4:
    movq    %rdx, %r8
    movl    %edi, %edx
    movl    %edi, %eax
    sarl    $31, %edx
    idivl   %esi
    movl    %eax, (%r8)
    movl    %edx, (%rcx)
    ret

测试div()和组合除法&我用gcc -O3编译了这些,我不得不添加对doNothing的调用来阻止编译器优化所有内容(对于除法+ mod解决方案,输出将为0)。

半信半疑:

#include <stdio.h>
#include <sys/time.h>
#include <stdlib.h>
extern doNothing(int,int); // Empty function in another compilation unit
int main() {
    int i;
    struct timeval timeval;
    struct timeval timeval2;
    div_t result;
    gettimeofday(&timeval,NULL);
    for (i = 0; i < 1000; ++i) {
        result = div(i,3);
        doNothing(result.quot,result.rem);
    }
    gettimeofday(&timeval2,NULL);
    printf("%d",timeval2.tv_usec - timeval.tv_usec);
}

输出:150

#include <stdio.h>
#include <sys/time.h>
#include <stdlib.h>
extern doNothing(int,int); // Empty function in another compilation unit
int main() {
    int i;
    struct timeval timeval;
    struct timeval timeval2;
    int dividend;
    int rem;
    gettimeofday(&timeval,NULL);
    for (i = 0; i < 1000; ++i) {
        dividend = i / 3;
        rem = i % 3;
        doNothing(dividend,rem);
    }
    gettimeofday(&timeval2,NULL);
    printf("%d",timeval2.tv_usec - timeval.tv_usec);
}

输出:25

除了前面提到的std::div系列函数之外,还有std::remquo系列函数,返回rem- der并通过传入指针获取quo- client。

[Edit:]看起来std::remquo并没有真正返回商。

在其他条件相同的情况下,最好的解决方案是清楚地表达你的意图。所以:

int totalSeconds = 453;
int minutes = totalSeconds / 60;
int remainingSeconds = totalSeconds % 60;

可能是您提供的三个选项中最好的。但是,正如在其他答案中所指出的那样,div方法将立即为您计算这两个值。

在32位intel平台上使用64位整数不能信任g++ 4.6.3。A/b通过调用divdi3计算,A %b通过调用moddi3计算。我甚至可以举出一个用这些调用计算a/b和a-b*(a/b)的例子。所以我用c=a/b和a-b*c。

div方法调用计算div结构的函数,但是函数调用在硬件支持整型的平台上似乎效率不高(例如64位的intel/amd平台上的64位整数)。

许多答案建议使用以下代码:

int div = a / b;
int mod = a % b;

然而,值得记住的是,除法与乘法不同,加法的执行时间要长得多(据我所知,与一个时钟周期相比,要花几十倍的时间)。并且,如果需要重复计算mod和div,则值得将两个除法替换为一个除法,一个乘法和一个加法,如下所示:

int div = a / b;
int mod = a - div * b;

您可以使用模数来获得余数。虽然@cnicutar的回答似乎更清晰/更直接。