Pregunta C ++ La mejor manera de obtener la división y el resto de enteros


Me pregunto, si quiero dividir a by b, y estoy interesado tanto en el resultado c como en el resto (por ejemplo, decir que tengo un número de segundos y quiero dividirlo en minutos y segundos), ¿cuál es la mejor manera de ir sobre eso?

Podría ser

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

o

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

o

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

o

tal vez hay una función mágica que le da a uno a la vez?


75
2017-08-15 20:21


origen


Respuestas:


En x86, el resto es un subproducto de la división misma, por lo que cualquier compilador medio decente debería ser capaz de usarlo (y no realizar un div de nuevo). Esto probablemente también se haga en otras arquitecturas.

Instrucción: DIV src

Nota: división sin signo. Divide el acumulador (AX) por "src". Si divisor   es un valor de byte, el resultado se pone a AL y resto a AH. Si divisor   es un valor de palabra, entonces DX: AX se divide por "src" y el resultado se almacena   en AX y el resto se almacena en DX.

int c = (int)a / b;
int d = a % b; /* Likely uses the result of the division. */

75
2017-08-15 20:23



std::div devuelve una estructura con resultado y resto.


59
2017-08-15 20:24



En x86 al menos, g ++ 4.6.1 simplemente usa IDIVL y obtiene ambas de esa instrucción única.

Código C ++:

void foo(int a, int b, int* c, int* d)
{
  *c = a / b;
  *d = a % b;
}

código x86:

__Z3fooiiPiS_:
LFB4:
    movq    %rdx, %r8
    movl    %edi, %edx
    movl    %edi, %eax
    sarl    $31, %edx
    idivl   %esi
    movl    %eax, (%r8)
    movl    %edx, (%rcx)
    ret

22
2017-08-15 20:41



Ejemplo de código de prueba div () y división combinada y mod. Los compilé con gcc -O3, tuve que agregar la llamada a doNothing para evitar que el compilador optimizara todo (la salida sería 0 para la solución de división + mod).

Tómelo con un grano de sal:

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

Salidas: 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);
}

Salidas: 25


8
2017-08-15 20:57



Además de lo mencionado anteriormente std :: div familia de funciones, también está el std :: remquo familia de funciones, devuelve el movimiento rápido del ojo-Ainder y obtener el quo-tiente a través de un puntero pasado.

[Editar:] Parece que std :: remquo realmente no devuelve el cociente después de todo.


5
2017-09-19 18:56



En igualdad de condiciones, la mejor solución es la que expresa claramente tu intención. Asi que:

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

es probablemente la mejor de las tres opciones que presentó. Como se señaló en otras respuestas, sin embargo, el div método calculará ambos valores para usted a la vez.


3
2017-08-15 20:27



Aquí no se puede confiar en g ++ 4.6.3 con enteros de 64 bits en una plataforma intel de 32 bits. a / b se calcula mediante una llamada a divdi3 y un% b se calcula mediante una llamada a moddi3. Incluso puedo encontrar un ejemplo que calcule a / b y a-b * (a / b) con estas llamadas. Entonces uso c = a / b y a-b * c.

El método div da una llamada a una función que calcula la estructura div, pero una llamada a función parece ineficaz en plataformas que tienen soporte de hardware para el tipo integral (es decir, enteros de 64 bits en plataformas intel / amd de 64 bits).


3
2018-05-04 01:38



Puedes usar un módulo para obtener el resto. Aunque la respuesta de @cnicutar parece más limpia / más directa.


-4
2017-08-15 20:26