This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
[RFC][BZ #15799] Make div cross-platform.
- From: OndÅej BÃlka <neleai at seznam dot cz>
- To: libc-alpha at sourceware dot org
- Date: Fri, 25 Oct 2013 20:21:01 +0200
- Subject: [RFC][BZ #15799] Make div cross-platform.
- Authentication-results: sourceware.org; auth=none
Hi, following bug report complains that division does not satisfy c
standard.
Following fix uses unsigned division for defined behavior. My original
view was that this code is not performance critical as gcc expands div
calls. However this is false as following is not optimized.
#include <stdlib.h>
int foo(int x, int y){
div_t d = div (x, 3);
return d.quot + d.rem;
}
This should be fast when both numerator and denumerators are positive,
is trying to optimize it more worth it?
[BZ #15799]
* stdlib/div.c (div): Compute result in cross-platform way.
diff --git a/stdlib/div.c b/stdlib/div.c
index 44a30a7..db3a7d0 100644
--- a/stdlib/div.c
+++ b/stdlib/div.c
@@ -55,31 +55,40 @@ div (numer, denom)
int numer, denom;
{
div_t result;
-
- result.quot = numer / denom;
- result.rem = numer % denom;
+ unsigned int unumer = numer, udenom = denom;
/* The ANSI standard says that |QUOT| <= |NUMER / DENOM|, where
NUMER / DENOM is to be computed in infinite precision. In
other words, we should always truncate the quotient towards
zero, never -infinity. Machine division and remainer may
work either way when one or both of NUMER or DENOM is
- negative. If only one is negative and QUOT has been
- truncated towards -infinity, REM will have the same sign as
- DENOM and the opposite sign of NUMER; if both are negative
- and QUOT has been truncated towards -infinity, REM will be
- positive (will have the opposite sign of NUMER). These are
- considered `wrong'. If both are NUM and DENOM are positive,
- RESULT will always be positive. This all boils down to: if
- NUMER >= 0, but REM < 0, we got the wrong answer. In that
- case, to get the right answer, add 1 to QUOT and subtract
- DENOM from REM. */
-
- if (numer >= 0 && result.rem < 0)
- {
- ++result.quot;
- result.rem -= denom;
- }
+ negative. We use unsigned division which has defined behaviour. */
+ if (numer >= 0)
+ if (denom >= 0)
+ {
+ result.quot = unumer / udenom;
+ result.rem = unumer % udenom;
+ }
+ else
+ {
+ udenom = - udenom;
+ result.quot = - (unumer / udenom);
+ result.rem = - (unumer % udenom);
+ }
+ else
+ if (denom >= 0)
+ {
+ unumer = - unumer;
+ result.quot = - (unumer / udenom);
+ result.rem = - (unumer % udenom);
+ }
+ else
+ {
+ unumer = - unumer;
+ udenom = - udenom;
+ result.quot = unumer / udenom;
+ result.rem = unumer % udenom;
+ }
return result;
}