C ++ Лучший способ получить целочисленное деление и остаток - PullRequest
89 голосов
/ 16 августа 2011

Мне просто интересно, если я хочу разделить a на b, и меня интересует как результат c, так и остаток (например, скажем, у меня есть количество секунд и я хочу разделить это на минуты и секунды), что это за лучший способ сделать это?

Было бы

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

или

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

или

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

или

может быть, есть магическая функция, которая дает и то и другое одновременно?

Ответы [ 8 ]

87 голосов
/ 16 августа 2011

На x86 остаток является побочным продуктом самого деления, поэтому любой полуприличный компилятор должен иметь возможность просто использовать его (и больше не выполнять div) Это возможно и на других архитектурах.

Инструкция: DIV SRC

Примечание: беззнаковое деление. Делит аккумулятор (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. */
69 голосов
/ 16 августа 2011

std::div возвращает структуру с результатом и остатком.

24 голосов
/ 16 августа 2011

По крайней мере, на 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
9 голосов
/ 16 августа 2011

Пример кода тестирования div () и комбинированного деления и мод. Я скомпилировал их с помощью gcc -O3, мне пришлось добавить вызов doNothing, чтобы не дать компилятору оптимизировать все (выходной сигнал будет равен 0 для решения Division + Mod).

Возьми это с зерном соли:

#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

5 голосов
/ 19 сентября 2014

В дополнение к вышеупомянутому семейству функций std :: div существует также семейство std :: remquo функции, возвращают rem -приемник и получают quo -приемник через переданный указатель.

[Edit:] Это выглядиткак std :: remquo на самом деле не возвращает частное в конце концов.

3 голосов
/ 04 мая 2014

Вы не можете доверять g ++ 4.6.3 здесь с 64-битными целыми числами на 32-битной платформе Intel.a / b вычисляется вызовом divdi3, а% b вычисляется вызовом moddi3.Я даже могу придумать пример, который вычисляет a / b и ab * (a / b) с этими вызовами.Поэтому я использую c = a / b и ab * c.

Метод div вызывает функцию, которая вычисляет структуру div, но вызов функции кажется неэффективным на платформах, которые имеют аппаратную поддержку целочисленного типа (то есть 64-битные целые на 64-битных платформах intel / amd).

3 голосов
/ 16 августа 2011

При прочих равных, лучшим решением будет то, которое четко выражает ваши намерения.Итак:

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

, вероятно, лучший из трех представленных вами вариантов.Однако, как отмечалось в других ответах, метод div рассчитает для вас оба значения одновременно.

0 голосов
/ 16 августа 2011

Вы можете использовать модуль, чтобы получить остаток.Хотя ответ @ cnicutar кажется чище / более прямым.

...