Reputation: 579
Is there a specific reason to use ldiv or div instead of '/' or '%' to divide/modulus two variables?
Upvotes: 37
Views: 5088
Reputation: 67283
The idea is that results from / and % can be determined from a single DIV instruction on the processor. So, historically, div() is used to provide an optimized way to get both.
However, I have found that newer compilers are able to optimize a / and % operation into a single divide anyway. For example, I've seen this optimization on Microsoft Visual C++. In these cases, div() really doesn't provide an advantage and, in fact, may even be slower if a call is involved.
Upvotes: 27
Reputation: 51
Okay, this is older, but I just stumbled here. The most important difference here is: The result of div() is defined. The C standard does not say how to round the quotient. That is because the compiler should be able to use the machine's implementation which depends on the CPU. Two different implementations exist: - rounding towards -infinity - rounding towards 0 .
div(), however is specified to do the latter, and is therefore portable.
Upvotes: 0
Reputation: 6991
Short answer : not really in a modern environment.
People have explained why benefit of div
is weak or even non-existent.
It's actually even worse : div
and friends introduce type coupling which hurts good practice (see drawback section below).
As said in other answers, calling div
instead of /
and %
most probably ensures that the operation is only done once at assembly level.
But in most modern contexts:
div
, if any, is generally negligible./
and %
modern compilers do the right thing anyway by generating only one division instruction fetching quotient and remainder from that. => No actual benefit for div
.If the exact type of the numbers (e.g. int
or long
) are statically known (that is, your code explicitly uses int or long always), using div
for int
and ldiv
for long is okay.
But if you follow the good practice of programming in small parts avoiding unneeded assumptions, you quickly realize that using div
and ldiv
ties the code to types int
or long
respectively. On the contrary, /
and %
will automatically adjust to whatever type is actually used in the case at hand, keeping code cleaner.
This is especially visible in two cases :
typedef
to abstract away actual types -- div
is clumsy even in C !div
defeats templates.The sample below shows that code using '/' and '%' is clean, simple, and not tied to int, long, long long or whatever, whereas code using div
and friends becomes clumsy.
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.
Source code:
#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 );
}
Upvotes: 5
Reputation: 263047
That's supposed to be faster than using the /
and %
operators if you want to compute both the quotient and the remainder at the same time.
Upvotes: 9
Reputation: 355207
Yes. C99 §7.20.6.2/2 says:
The
div
,ldiv
, andlldiv
, functions computenumer / denom
andnumer % denom
in a single operation.
Upvotes: 27