linux/lib/div64.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2003 Bernardo Innocenti <bernie@develer.com>
   3 *
   4 * Based on former do_div() implementation from asm-parisc/div64.h:
   5 *      Copyright (C) 1999 Hewlett-Packard Co
   6 *      Copyright (C) 1999 David Mosberger-Tang <davidm@hpl.hp.com>
   7 *
   8 *
   9 * Generic C version of 64bit/32bit division and modulo, with
  10 * 64bit result and 32bit remainder.
  11 *
  12 * The fast case for (n>>32 == 0) is handled inline by do_div(). 
  13 *
  14 * Code generated for this function might be very inefficient
  15 * for some CPUs. __div64_32() can be overridden by linking arch-specific
  16 * assembly versions such as arch/ppc/lib/div64.S and arch/sh/lib/div64.S.
  17 */
  18
  19#include <linux/module.h>
  20#include <linux/math64.h>
  21
  22/* Not needed on 64bit architectures */
  23#if BITS_PER_LONG == 32
  24
  25uint32_t __attribute__((weak)) __div64_32(uint64_t *n, uint32_t base)
  26{
  27        uint64_t rem = *n;
  28        uint64_t b = base;
  29        uint64_t res, d = 1;
  30        uint32_t high = rem >> 32;
  31
  32        /* Reduce the thing a bit first */
  33        res = 0;
  34        if (high >= base) {
  35                high /= base;
  36                res = (uint64_t) high << 32;
  37                rem -= (uint64_t) (high*base) << 32;
  38        }
  39
  40        while ((int64_t)b > 0 && b < rem) {
  41                b = b+b;
  42                d = d+d;
  43        }
  44
  45        do {
  46                if (rem >= b) {
  47                        rem -= b;
  48                        res += d;
  49                }
  50                b >>= 1;
  51                d >>= 1;
  52        } while (d);
  53
  54        *n = res;
  55        return rem;
  56}
  57
  58EXPORT_SYMBOL(__div64_32);
  59
  60#ifndef div_s64_rem
  61s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder)
  62{
  63        u64 quotient;
  64
  65        if (dividend < 0) {
  66                quotient = div_u64_rem(-dividend, abs(divisor), (u32 *)remainder);
  67                *remainder = -*remainder;
  68                if (divisor > 0)
  69                        quotient = -quotient;
  70        } else {
  71                quotient = div_u64_rem(dividend, abs(divisor), (u32 *)remainder);
  72                if (divisor < 0)
  73                        quotient = -quotient;
  74        }
  75        return quotient;
  76}
  77EXPORT_SYMBOL(div_s64_rem);
  78#endif
  79
  80/**
  81 * div64_u64 - unsigned 64bit divide with 64bit divisor
  82 * @dividend:   64bit dividend
  83 * @divisor:    64bit divisor
  84 *
  85 * This implementation is a modified version of the algorithm proposed
  86 * by the book 'Hacker's Delight'.  The original source and full proof
  87 * can be found here and is available for use without restriction.
  88 *
  89 * 'http://www.hackersdelight.org/HDcode/newCode/divDouble.c'
  90 */
  91#ifndef div64_u64
  92u64 div64_u64(u64 dividend, u64 divisor)
  93{
  94        u32 high = divisor >> 32;
  95        u64 quot;
  96
  97        if (high == 0) {
  98                quot = div_u64(dividend, divisor);
  99        } else {
 100                int n = 1 + fls(high);
 101                quot = div_u64(dividend >> n, divisor >> n);
 102
 103                if (quot != 0)
 104                        quot--;
 105                if ((dividend - quot * divisor) >= divisor)
 106                        quot++;
 107        }
 108
 109        return quot;
 110}
 111EXPORT_SYMBOL(div64_u64);
 112#endif
 113
 114/**
 115 * div64_s64 - signed 64bit divide with 64bit divisor
 116 * @dividend:   64bit dividend
 117 * @divisor:    64bit divisor
 118 */
 119#ifndef div64_s64
 120s64 div64_s64(s64 dividend, s64 divisor)
 121{
 122        s64 quot, t;
 123
 124        quot = div64_u64(abs64(dividend), abs64(divisor));
 125        t = (dividend ^ divisor) >> 63;
 126
 127        return (quot ^ t) - t;
 128}
 129EXPORT_SYMBOL(div64_s64);
 130#endif
 131
 132#endif /* BITS_PER_LONG == 32 */
 133
 134/*
 135 * Iterative div/mod for use when dividend is not expected to be much
 136 * bigger than divisor.
 137 */
 138u32 iter_div_u64_rem(u64 dividend, u32 divisor, u64 *remainder)
 139{
 140        return __iter_div_u64_rem(dividend, divisor, remainder);
 141}
 142EXPORT_SYMBOL(iter_div_u64_rem);
 143