С++ Лучший способ получить целочисленное деление и остаток
Мне просто интересно, если я хочу разделить 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);
или
может быть, есть волшебная функция, которая дает одно одновременно?
Ответы
Ответ 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
Ответ 5
В дополнение к вышеупомянутому семейству функций std:: div существует также std:: remquo семейство функций, верните rem и получите quo -tient с помощью переданного указателя.
[Edit:] Похоже, что std:: remquo действительно не возвращает значение.
Ответ 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 кажется более чистым/более прямым.