aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorRandolph Chung <tausq@debian.org>2003-10-25 22:27:04 -0800
committerLinus Torvalds <torvalds@home.osdl.org>2003-10-25 22:27:04 -0800
commitc2988baf02a8a29f0224115b10e575b826d5abcd (patch)
tree6031754a717ee916b41238a271a6a6007135365a /lib
parentd33648efb3b41924dd0dd750650de9923bb5724e (diff)
downloadhistory-c2988baf02a8a29f0224115b10e575b826d5abcd.tar.gz
[PATCH] fix __div64_32 to do division properly
This fixes the generic __div64_32() to correctly handle divisions by large 32-bit values (as used by nanosleep() and friends, for example). It's a simple bit-at-a-time implementation with a reduction of the high 32-bits handled manually. Architectures that can do 64/32-bit divisions in hardware should implement their own more efficient versions.
Diffstat (limited to 'lib')
-rw-r--r--lib/div64.c47
1 files changed, 28 insertions, 19 deletions
diff --git a/lib/div64.c b/lib/div64.c
index d8c699e1f70ec7..365719f84832dc 100644
--- a/lib/div64.c
+++ b/lib/div64.c
@@ -25,25 +25,34 @@
uint32_t __div64_32(uint64_t *n, uint32_t base)
{
- uint32_t low, low2, high, rem;
-
- low = *n & 0xffffffff;
- high = *n >> 32;
- rem = high % (uint32_t)base;
- high = high / (uint32_t)base;
- low2 = low >> 16;
- low2 += rem << 16;
- rem = low2 % (uint32_t)base;
- low2 = low2 / (uint32_t)base;
- low = low & 0xffff;
- low += rem << 16;
- rem = low % (uint32_t)base;
- low = low / (uint32_t)base;
-
- *n = low +
- ((uint64_t)low2 << 16) +
- ((uint64_t)high << 32);
-
+ uint64_t rem = *n;
+ uint64_t b = base;
+ uint64_t res, d = 1;
+ uint32_t high = rem >> 32;
+
+ /* Reduce the thing a bit first */
+ res = 0;
+ if (high >= base) {
+ high /= base;
+ res = (uint64_t) high << 32;
+ rem -= (uint64_t) (high*base) << 32;
+ }
+
+ while ((int64_t)b > 0 && b < rem) {
+ b = b+b;
+ d = d+d;
+ }
+
+ do {
+ if (rem >= b) {
+ rem -= b;
+ res += d;
+ }
+ b >>= 1;
+ d >>= 1;
+ } while (d);
+
+ *n = res;
return rem;
}