开发者

efficient way to divide ignoring rest

开发者 https://www.devze.com 2023-03-22 15:21 出处:网络
there are 2 ways i found to get a whole numb开发者_运维知识库er from a division in c++ question is which way is more efficient (more speedy)

there are 2 ways i found to get a whole numb开发者_运维知识库er from a division in c++

question is which way is more efficient (more speedy)

first way:

Quotient = value1 / value2;  // normal division haveing splitted number

floor(Quotient);             // rounding the number down to the first integer

second way:

Rest = value1 % value2;             // getting the Rest with modulus % operator

Quotient = (value1-Rest) / value2;  // substracting the Rest so the division will match

also please demonstrate how to find out which method is faster


If you're dealing with integers, then the usual way is

Quotient = value1 / value2;

That's it. The result is already an integer. No need to use the floor(Quotient); statement. It has no effect anyway. You would want to use Quotient = floor(Quotient); if it was needed.

If you have floating point numbers, then the second method won't work at all, as % is only defined for integers. But what does it mean to get a whole number from a division of real numbers? What integer do you get when you divide 8.5 by 3.2? Does it ever make sense to ask this question?

As a side note, the thing you call 'Rest' is normally called 'reminder'.remainder.


Use this program:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#ifdef DIV_BY_DIV
#define DIV(a, b) ((a) / (b))
#else
#define DIV(a, b) (((a) - ((a) % (b))) / (b))
#endif

#ifndef ITERS
#define ITERS 1000
#endif

int main()
{
    int i, a, b;

    srand(time(NULL));
    a = rand();
    b = rand();

    for (i = 0; i < ITERS; i++)
        a = DIV(a, b);

    return 0;
}

You can time execution

mihai@keldon:/tmp$ gcc -Wall -Wextra -DITERS=1000000 -DDIV_BY_DIV 1.c && time ./a.out 

real    0m0.010s
user    0m0.012s
sys     0m0.000s
mihai@keldon:/tmp$ gcc -Wall -Wextra -DITERS=1000000 1.c && time ./a.out 

real    0m0.019s
user    0m0.020s
sys     0m0.000s

Or, you look at the assembly output:

mihai@keldon:/tmp$ gcc -Wall -Wextra -DITERS=1000000 -DDIV_BY_DIV 1.c -S; mv 1.s 1_div.s 
mihai@keldon:/tmp$ gcc -Wall -Wextra -DITERS=1000000 1.c -S; mv 1.s 1_modulus.s 
mihai@keldon:/tmp$ diff 1_div.s 1_modulus.s 
24a25,32
>   movl    %edx, %eax
>   movl    24(%esp), %edx
>   movl    %edx, %ecx
>   subl    %eax, %ecx
>   movl    %ecx, %eax
>   movl    %eax, %edx
>   sarl    $31, %edx
>   idivl   20(%esp)

As you see, doing only the division is faster.

Edited to fix error in code, formatting and wrong diff.

More edit (explaining the assembly diff): In the second case, when doing the modulus first, the assembly shows that two idivl operations are needed: one to get the result of % and one for the actual division. The above diff shows the subtraction and the second division, as the first one is exactly the same in both codes.

Edit: more relevant timing information:

mihai@keldon:/tmp$ gcc -Wall -Wextra -DITERS=42000000 -DDIV_BY_DIV 1.c && time ./a.out 

real    0m0.384s
user    0m0.360s
sys     0m0.004s
mihai@keldon:/tmp$ gcc -Wall -Wextra -DITERS=42000000 1.c && time ./a.out 

real    0m0.706s
user    0m0.696s
sys     0m0.004s

Hope it helps.

Edit: diff between assembly with -O0 and without.

mihai@keldon:/tmp$ gcc -Wall -Wextra -DITERS=1000000 1.c -S -O0; mv 1.s O0.s
mihai@keldon:/tmp$ gcc -Wall -Wextra -DITERS=1000000 1.c -S; mv 1.s noO.s
mihai@keldon:/tmp$ diff noO.s O0.s 

Since the defualt optimization level of gcc is O0 (see this article explaining optimization levels in gcc) the result was expected.

Edit: if you compile with -O3 as one of the comments suggested you'll get the same assembly, at that level of optimization, both alternatives are the same.

0

精彩评论

暂无评论...
验证码 换一张
取 消