简体   繁体   English

是否有一个c ++函数(内置或其他)给出整数除法和模块除法结果而不重复操作?

[英]Is there a c++ function (built-in or otherwise) that gives the integer division and modular division results without repeating the operation?

You could write something like: 你可以这样写:

int i = 3;
int k = 2;
int division = i / k;
int remainder = i % k;

It seems as thought this would, on a low level, ask an ALU to perform two vision operations: one returning the quotient, and one returning the remainder. 似乎认为这将在低级别上要求ALU执行两个视觉操作:一个返回商,一个返回余数。 However, I believe an ALU would most likely calculate both in a single operation. 但是,我相信ALU最有可能在一次操作中计算两者。 If that is the case, this is not optimally efficient. 如果是这种情况,这不是最佳效率。

Is there a more efficient way of doing it, without asking the CPU to calculate twice? 是否有更有效的方法,而不要求CPU计算两次? In other words, can it be done in a single operation from C++? 换句话说,它可以在C ++的单个操作中完成吗?

Actually, the code you wrote won't generate any division instructions since the compiler can figure out the results at compile time. 实际上,您编写的代码不会生成任何除法指令,因为编译器可以在编译时计算出结果。 I wrote a little test program and set the compiler (VC++ 10SP1) to generate an assembly code listing. 我写了一个小测试程序并设置编译器(VC ++ 10SP1)来生成汇编代码清单。

#include <iostream>

using namespace std;

struct result {
    long quotient, remainder;
};

result divide(long num, long den) {
    result d = { num / den, num % den };
    return d;
}

int main() {
    result d = divide(3, 2);
    d = divide(10, 3);
    cout << d.quotient << " : " << d.remainder << endl;
    return 0;
}

I had to write it this way and explicitly tell the compiler to not inline any functions. 我必须以这种方式编写它,并明确告诉编译器不要内联任何函数。 Otherwise the compiler would have happily optimized away most of the code. 否则编译器会愉快地优化大部分代码。 Here is the resulting assembly code for the divide function. 以下是除法函数的结果汇编代码。

; 8    : result divide(long num, long den) {

  00000 55       push    ebp
  00001 8b ec        mov     ebp, esp

; 9    :     result d = { num / den, num % den };

  00003 99       cdq
  00004 f7 7d 08     idiv    DWORD PTR _den$[ebp]

; 10   :     return d;
; 11   : }

  00007 5d       pop     ebp
  00008 c3       ret     0

It's smart enough to generate a single IDIV instruction and use the quotient and remainder generated by it. 它足够聪明,可以生成单个IDIV指令并使用它生成的商和余数。 Modern C and C++ compilers have gotten really good at this sort of optimization. 现代C和C ++编译器在这种优化方面已经非常擅长。 Unless you have a performance problem and have profiled your code to determine where the bottleneck is, don't try to second guess the compiler. 除非您遇到性能问题并且已经分析了代码以确定瓶颈在哪里,否则不要试图再次猜测编译器。

Sure: 当然:

int i = 3;
int k = 2;
int division = i / k;
int remainder = i - division * k;

Also, if you really want to do this, look at div , I doubt it's faster though, just like my above solution. 另外,如果你真的想这样做,看看div ,我怀疑它更快,就像我上面的解决方案一样。

ISO C99 has the ldiv function: ISO C99具有ldiv功能:

#include <stdlib.h>

ldiv_t ldiv(long numer, long denom);

The ldiv() function computes the value numer/denom (numerator/denominator).
It returns the quotient and remainder in a structure named ldiv_t that contains
two long members named quot and rem.

Whether at the FPU level that reduces to a single operation I couldn't say. 无论是在FPU级别还是单一操作我都说不出来。

I'm not aware of anything built-in, but you can simulate it with a multiply instead of a divide: 我不知道内置任何东西,但你可以用乘法而不是除法来模拟它:

int division = i / k;
int remainder = i - (division * k);

When you ask yourself, what is fastest, it's usually a good idea to benchmark it (I like to do that). 当你问自己什么是最快的时候,通常一个好主意就是对它进行基准测试(我喜欢这样做)。 So I took the answers from here and wrote a tiny benchmarking program and threw it at gcc (similar results would be expected for g++ I think) at -O0 (at -O1 he optimises everything away and my benchmark is broken). 所以我从这里得到了答案并编写了一个很小的基准测试程序,然后把它扔到了gcc (我认为g++会有类似的结果) -O0 (在-O1他优化了一切,我的基准测试被破坏了)。

I performed 2^28 runs (both i and k running from 1 to 2^14 ) on my laptop and got the following runtimes: 我在笔记本电脑上执行了2^28次运行( ik运行从12^14 )并获得以下运行时:

division = 0;
remainder = 0;
// this test is only there to measure the constant overhead!

1.676s 1.676s

division = i/k;
remainder = i%k;

24.614s 24.614s

division = i/k;
remainder = i - division*k;

15.009s 15.009s

ldiv_t d = ldiv(i,k);
division = d.quot;
remainder = d.rem;

18.845s 18.845s

As one can see, there is a difference and your best shot is the multiplication approach. 正如人们所看到的, 有区别的,你的最好的拍摄是乘法的方法。 The ldiv approach is also okay, but I find it slightly cumbersome compared to the others. ldiv方法也没关系,但我发现它与其他方法相比有点麻烦。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM