diff options
author | Randolph Chung <tausq@debian.org> | 2003-10-25 22:27:04 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@home.osdl.org> | 2003-10-25 22:27:04 -0800 |
commit | c2988baf02a8a29f0224115b10e575b826d5abcd (patch) | |
tree | 6031754a717ee916b41238a271a6a6007135365a /lib | |
parent | d33648efb3b41924dd0dd750650de9923bb5724e (diff) | |
download | history-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.c | 47 |
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; } |