C++获得整数除法和余数的最佳方法

Coo*_*kie 91 c++ division

我只是想知道,如果我想将a除以b,并且对结果c和余数感兴趣(例如说我有秒数并希望将其分成几分钟和几秒),那么最好的方法是什么去吧?

可不可能是

int c = (int)a / b;
int d = a % b;
Run Code Online (Sandbox Code Playgroud)

要么

int c = (int)a / b;
int d = a - b * c;
Run Code Online (Sandbox Code Playgroud)

要么

double tmp = a / b;
int c = (int)tmp;
int d = (int)(0.5+(tmp-c)*b);
Run Code Online (Sandbox Code Playgroud)

要么

也许有一个神奇的功能同时给出一个?

cni*_*tar 87

在x86上,余数是除法本身的副产品,因此任何半合适的编译器都应该能够使用它(而不是div再次执行).这可能也是在其他架构上完成的.

说明:DIVsrc

注意:无符号除法.将累加器(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. */
Run Code Online (Sandbox Code Playgroud)

  • 我试过一个快速测试.使用-++的g ++ 4.3.2,汇编器输出使用一个`idivl`指令清楚地显示它并使用eax和edx中的结果.如果没有,我会感到震惊. (57认同)
  • 我想很多小学生从小学就知道,在做分工时,你可以免费获得其余部分.真正的问题是:我们的编译器是否足够智能以利用这一点? (7认同)
  • @EuriPinhollow同意这不是关于x86的问题.我只是把它作为一个例子,高度可疑的假设是其他架构可能做类似的事情. (2认同)
  • 但是,您需要告诉编译器优化,至少对于g ++.在x86_64上使用g ++ 6.3.0进行的一个简单实验表明,在没有优化的情况下,你会得到两个"idivl"指令,但是使用`-O1`或更高版本,你得到一个.正如手册所说,["没有任何优化选项......声明是独立的"](https://gcc.gnu.org/onlinedocs/gcc-6.4.0/gcc/Optimize-Options.html). (2认同)

pez*_*ode 71

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

  • 我很想知道这是否比现代编译器上的选项1更有效. (4认同)
  • 看起来很有效率。cppreference 表示,“在许多平台上,单个 CPU 指令同时获取商和余数,并且该函数可以利用这一点,尽管编译器通常能够在合适的地方合并附近的 / 和 %。” (3认同)
  • 很好,我不知道.它更快吗? (2认同)
  • 我不在乎它是否更快。*它更具可读性*。同时使用`/`和`%`,你将会有代码重复或者除数和被除数的额外变量,没有经验的读者可能会问:这会被优化吗?`std::div` 更清晰,减少了歧义和冗余。对于结构化绑定,使用起来非常优雅:`const auto [q, r] = std::div(divisor,divid);` (2认同)
  • @pasbi 该文档明确排除了对商和余数假设特定的内存顺序。 (2认同)

Pet*_*der 25

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

C++代码:

void foo(int a, int b, int* c, int* d)
{
  *c = a / b;
  *d = a % b;
}
Run Code Online (Sandbox Code Playgroud)

x86代码:

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


Gre*_*ell 9

示例代码测试div()和组合分区和mod.我使用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);
}
Run Code Online (Sandbox Code Playgroud)

产出: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);
}
Run Code Online (Sandbox Code Playgroud)

产出:25


Jam*_*rey 5

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

[编辑:]看起来std :: remquo毕竟不会真正返回商数.