эффективный способ разделить игнорируя отдых - PullRequest
1 голос
/ 23 июля 2011

я нашел 2 способа получить целое число из деления в c ++

вопрос в том, какой путь более эффективен (более быстр)

первый путь:

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

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

второй способ:

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

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

также, пожалуйста, продемонстрируйте, как узнать, какой метод быстрее

Ответы [ 2 ]

5 голосов
/ 23 июля 2011

Если вы имеете дело с целыми числами, то обычным способом будет

Quotient = value1 / value2;

Вот и все. Результат уже целое число. Нет необходимости использовать оператор floor(Quotient);. Это никак не влияет. Вы хотели бы использовать Quotient = floor(Quotient);, если это было необходимо.

Если у вас есть числа с плавающей запятой, то второй метод вообще не будет работать, так как % определен только для целых чисел. Но что это значит, чтобы получить целое число от деления действительных чисел? Какое целое число вы получаете, когда вы делите 8,5 на 3,2? Есть ли смысл задавать этот вопрос?

Как примечание: то, что вы называете «Отдыхом», обычно называется «напоминание». остаток.

1 голос
/ 23 июля 2011

Используйте эту программу:

#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;
}

Вы можете время выполнения

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

Или, вы посмотрите на вывод сборки:

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)

Как вы видитевыполнение только деления происходит быстрее.

Отредактировано для исправления ошибки в коде, форматирования и неправильного сравнения.

Больше редактирования (объяснение различий в сборке): во втором случае, когда выполняется модульво-первых, сборка показывает, что необходимы две операции idivl: одна для получения результата % и одна для фактического деления.Приведенная выше разница показывает вычитание и второе деление, поскольку первое в обоих кодах абсолютно одинаковое.

Редактировать: более актуальная информация о времени:

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

Надеюсь, это поможет.

Редактировать: разница между сборками с -O0 и без.

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 

Поскольку уровень оптимизации по умолчанию gcc равен O0 (см. в этой статье, поясняющие уровни оптимизации вgcc) ожидаемый результат.

Редактировать: если вы скомпилируете с -O3, как один из комментариев, вы получите ту же сборку, на этом уровне оптимизации, обе альтернативыто же самое.

...