Existe-t-il une raison spécifique d'utiliser ldiv ou div au lieu de '/' ou '%' pour diviser / moduler deux variables?
Réponses
Trop de publicités?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é.
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:
- 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. - 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 );
}
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.