35 votes

Pourquoi utiliser div ou ldiv en C / C ++?

Existe-t-il une raison spécifique d'utiliser ldiv ou div au lieu de '/' ou '%' pour diviser / moduler deux variables?

27voto

James McNellis Points 193607

Oui. C99 §7.20.6.2 / 2 dit:

Les fonctions div , ldiv et lldiv calculent numer / denom et numer % denom en une seule opération.

26voto

Jonathan Wood Points 26443

L'idée est que les résultats de / et% peuvent être déterminés à partir d'une seule instruction DIV sur le processeur. Ainsi, historiquement, div () est utilisé pour fournir un moyen optimisé d’obtenir les deux.

Cependant, j'ai constaté que les nouveaux compilateurs sont capables d'optimiser une opération / et% dans une division unique de toute façon. Par exemple, j'ai vu cette optimisation sur Microsoft Visual C ++. Dans ces cas, div () ne fournit vraiment aucun avantage et, en fait, peut même être lent si un appel est impliqué.

9voto

Frédéric Hamidi Points 123646

Cela est supposé être plus rapide que d'utiliser les opérateurs / et % si vous souhaitez calculer le quotient et le reste en même temps.

4voto

Réponse courte : non, pas vraiment dans un environnement moderne.

Les gens ont expliqué pourquoi bénéfice de l' div est faible, voire inexistante. C'est même pire : div et les amis introduire type de couplage qui fait mal aux bonnes pratiques (voir inconvénient section ci-dessous).

Avantage : probablement aucun

Comme dit dans d'autres réponses, en appelant div au lieu de / et % plus probablement s'assure que l'opération est effectuée qu'une seule fois au niveau de l'assemblée.

Mais dans la plupart des modernes contextes:

  1. Le PROCESSEUR est donc bien optimisé opérations mathématiques qui, sauf dans les recoins les plus profonds de la boucle d'un calcul fait des centaines de fois, un gain de performance en répétant l'opération est probablement beaucoup plus petite que les autres performances (comme d'autres le code de autour de, le cache, etc.). => Avantage de l' div, le cas échéant, est généralement négligeable.
  2. Même lors de l'utilisation d' / et % les compilateurs modernes faire la bonne chose, de toute façon par la génération d'une division d'instruction de l'extraction de quotient et le reste de cette. => Pas de bénéfice réel pour l' div.

Inconvénient : div et les amis de la cravate de votre code pour un type spécifique

Si le type exact des nombres (par exemple, int ou long) sont statiquement connu (c'est-à-votre code utilise explicitement int ou long toujours), à l'aide de div pour int et ldiv pour les longues est d'accord.

Mais si vous suivez les bonnes pratiques de la programmation dans les petites pièces en évitant les hypothèses inutiles, vous vous apercevrez rapidement qu'à l'aide de div et ldiv liens le code pour les types d' int ou long respectivement. Au contraire, / et % ajustera automatiquement à tout type est effectivement utilisée dans le cas à la main, en gardant code plus propre.

Cela est particulièrement visible dans deux cas :

  • vous utilisez typedef faire abstraction des types réels -- div est maladroit, même en C !
  • vous utilisez des modèles de faire abstraction des types réels -- div de défaites modèles.

Exemple

L'exemple ci-dessous montre que le code à l'aide de '/' et '%' est propre, simple, et ne sont pas liés à l'int, long, long long ou que ce soit, alors que le code à l'aide div et amis devient maladroit.

Testing with int
my_math_func_div_WRONG  says 6
my_math_func_OVERKILL   says 6  // Works but overkill cast to long
my_math_func_GOOD   says 6      // No div no headache.

Testing with int in long type
my_math_func_div_WRONG  says 6
my_math_func_OVERKILL   says 6  // Works but overkill cast to long
my_math_func_GOOD   says 6      // No div no headache.

Testing with actual long
my_math_func_div_WRONG  says 70503280   // FAIL
my_math_func_OVERKILL   says 500000006
my_math_func_GOOD   says 500000006      // No div no headache.

Code Source:

#include <iostream>

// '/' and '%' are smart about type.
// This code is simple and will work with int, long, longlong, char, whatever.
template<typename T>
T my_math_func_GOOD( T number )
{
    T quotient = number / 10;
    T remainder = number % 10;
    // do something
    return quotient + remainder;
}

// div and friends are not smart about type.
// How do you write code smart about type with them ?

// Plus adds dependency on C's stdlib.
#include <stdlib.h>
template<typename T>
T my_math_func_div_WRONG( T number )
{
    // This will always downcast to int. Defeats purpose of template.
    div_t result = div( number, 10 );
    T quotient = result.quot;
    T remainder = result.rem;
    // do something
    return quotient + remainder;
}

template<typename T>
T my_math_func_OVERKILL( T number )
{
    // This will always cast to long (up from int, OVERKILL, possibly down from long long, FAIL). Defeats purpose of template.
    ldiv_t result = ldiv( number, 10 );
    T quotient = result.quot;
    T remainder = result.rem;
    // do something
    return quotient + remainder;
}

template<typename T>
void my_math_func_test( T number )
{
    T n;
    n = my_math_func_div_WRONG( number );
    std::cout << "my_math_func_div_WRONG\tsays " << n << std::endl; // writes 6
    n = my_math_func_OVERKILL( number );
    std::cout << "my_math_func_OVERKILL\tsays " << n << std::endl; // writes 6
    n = my_math_func_GOOD( number );
    std::cout << "my_math_func_GOOD\tsays " << n << std::endl; // writes 6
}

// C99 allows absence of int argc, char **argv
int main()
{
    std::cout << std::endl << "Testing with int" << std::endl;
    my_math_func_test<int>( 42 );
    std::cout << std::endl << "Testing with int in long type" << std::endl;
    my_math_func_test<long>( 42 );
    std::cout << std::endl << "Testing with actual long" << std::endl;
    my_math_func_test<long>( 5000000042 );
    // std::cout << std::endl << "Testing with long long" << std::endl;
    // my_math_func_test<long long>( 50000000000000000042 );
}

1voto

Jörg Neulist Points 21

Ok, c'est plus vieux, mais je viens de trébucher ici. La différence la plus importante ici est la suivante: Le résultat de div () est défini. La norme C ne dit pas comment arrondir le quotient. En effet, le compilateur devrait pouvoir utiliser l'implémentation de la machine, qui dépend du processeur. Il existe deux implémentations différentes: - arrondi vers -infini - arrondi vers 0.

div (), cependant, est spécifié pour faire ce dernier, et est donc portable.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X