C++ Best way to get integer division and remainder

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

是吗

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

或者

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

or

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

或者

maybe there is a magical function that gives one both at once?

283411 次浏览

在 x86上,其余部分是除法本身的副产品,因此任何一个不怎么样的编译器都应该能够只使用它(并且不再执行 div)。这可能在其他体系结构上也是这样做的。

使用说明: DIV src

注意: 无符号除法。用“ src”除累加器(AX)。如果除数 是一个字节值,结果放到 AL剩下的给 AH。如果除数 是一个单词值,然后 DX: AX 除以“ src”并存储 result in AX and remainder is stored in DX.

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

std::div 返回同时包含结果和余数的结构。

你可以使用一个模来求余数,尽管@cnicutar 的答案看起来更简洁/更直接。

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

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

可能是你提出的三个选择中最好的一个。然而,正如其他答案中提到的,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 ()和组合的 Division & mod。我用 gcc-O3编译了这些文件,我必须添加调用 doNothing 来阻止编译器优化所有内容(对于 Division + 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

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

Div 方法调用一个函数来计算 div 结构,但是在硬件支持整数类型的平台(即64位 Intel/amd 平台上的64位整数)上,函数调用似乎效率低下。

除了上面提到的 std::div函数族,还有 雷尔 = “ nofollow noReferrer”> 标准: : 雷姆柯函数族,返回 雷姆-ainder 并通过传入指针获得 维持现状-tient。

[ Edit: ] 看起来还是像 std: : Remquo 并不能真正返回商数

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

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

然而,值得记住的是,除法和乘法不同,加法的执行时间要长得多(据我所知,除法的时钟周期是一个时钟周期的几十倍)。而且,如果你需要反复计算 mod 和 div,那么用一个除法、一个乘法和一个加法来代替两个除法是值得的,如下所示:

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