web-dev-qa-db-fra.com

C ++ Meilleur moyen d'obtenir la division entière et le reste

Je me demande simplement, si je veux diviser a par b, et que le résultat c et le reste m'intéressent (par exemple, disons que j'ai le nombre de secondes et que je souhaite scinder cela en minutes et en secondes), quel est le meilleur moyen de aller à ce sujet?

Serait-ce

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

ou

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

ou

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

ou

peut-être y a-t-il une fonction magique qui donne les deux à la fois?

89
Cookie

Sur x86, le reste est un sous-produit de la division elle-même, donc tout compilateur à la moitié décente devrait pouvoir l'utiliser (et ne pas effectuer à nouveau div). Ceci est probablement fait sur d'autres architectures aussi.

Instruction: DIV src

Remarque: division non signée. Divise l'accumulateur (AX) par "src". Si diviseur est une valeur d'octet, le résultat est mis à AL et le reste à AH. Si diviseur est une valeur Word, alors DX: AXE est divisé par "src" et le résultat est stocké dans AX le reste est stocké dans DX.

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

std::div renvoie une structure avec à la fois le résultat et le reste.

70
pezcode

Sur au moins x86, g ++ 4.6.1 utilise simplement IDIVL et obtient les deux à partir de cette instruction unique.

Code C++:

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

code x86:

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

Exemple de code test div () et division & mod. Je les ai compilés avec gcc -O3, il a fallu ajouter l’appel à doNothing pour empêcher le compilateur d’optimiser l’optimisation totale (le résultat serait 0 pour la solution division + mod).

Prenez-le avec un grain de sel:

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

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

Sorties: 25

9
Greg Howell

En plus de la famille de fonctions std :: div susmentionnée, il existe également le groupe std :: remquo famille de fonctions, retourne le rem - ainder et récupère le quo - patient via un pointeur passé.

[Edit:] Cela ressemble à std :: remquo ne renvoie pas vraiment le quotient après tout.

5
Jamin Grey

Vous ne pouvez pas faire confiance à g ++ 4.6.3 ici avec des entiers 64 bits sur une plate-forme Intel 32 bits. a/b est calculé par un appel à divdi3 et un% b est calculé par un appel à moddi3. Je peux même trouver un exemple qui calcule a/b et a-b * (a/b) avec ces appels. Donc j'utilise c = a/b et a-b * c.

La méthode div appelle une fonction qui calcule la structure div, mais un appel de fonction semble inefficace sur les plates-formes prenant en charge le matériel pour le type intégral (c'est-à-dire des entiers 64 bits sur des plates-formes Intel/AMD 64 bits).

3
brac37

Toutes choses étant égales par ailleurs, la meilleure solution est celle qui exprime clairement votre intention. Alors:

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

est probablement la meilleure des trois options que vous avez présentées. Comme indiqué dans d'autres réponses cependant, la méthode div calculera les deux valeurs pour vous en même temps.

3
Jon