Подтвердить что ты не робот

С++ Лучший способ получить целочисленное деление и остаток

Мне просто интересно, если я хочу разделить 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);

или

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

4b9b3361

Ответ 1

На 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. */

Ответ 2

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

Ответ 3

В x86, по крайней мере, g++ 4.6.1 просто использует IDIVL и получает обе из этой единственной инструкции.

Код С++:

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

Ответ 4

Пример тестирования кода div() и комбинированного деления и мода. Я скомпилировал их с помощью gcc-O3, мне пришлось добавить вызов doNothing, чтобы остановить компилятор от оптимизации всего (выход будет 0 для решения с разделением + 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

Ответ 6

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

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

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

Ответ 7

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

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

Ответ 8

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