div64.c 2.3 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/*
 * Copyright (C) 2003 Bernardo Innocenti <bernie@develer.com>
 *
 * Based on former do_div() implementation from asm-parisc/div64.h:
 *	Copyright (C) 1999 Hewlett-Packard Co
 *	Copyright (C) 1999 David Mosberger-Tang <davidm@hpl.hp.com>
 *
 *
 * Generic C version of 64bit/32bit division and modulo, with
 * 64bit result and 32bit remainder.
 *
 * The fast case for (n>>32 == 0) is handled inline by do_div(). 
 *
 * Code generated for this function might be very inefficient
 * for some CPUs. __div64_32() can be overridden by linking arch-specific
 * assembly versions such as arch/ppc/lib/div64.S and arch/sh/lib/div64.S.
 */

#include <linux/module.h>
20
#include <linux/math64.h>
L
Linus Torvalds 已提交
21 22 23 24

/* Not needed on 64bit architectures */
#if BITS_PER_LONG == 32

D
David S. Miller 已提交
25
uint32_t __attribute__((weak)) __div64_32(uint64_t *n, uint32_t base)
L
Linus Torvalds 已提交
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
{
	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;
}

EXPORT_SYMBOL(__div64_32);

60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
#ifndef div_s64_rem
s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder)
{
	u64 quotient;

	if (dividend < 0) {
		quotient = div_u64_rem(-dividend, abs(divisor), (u32 *)remainder);
		*remainder = -*remainder;
		if (divisor > 0)
			quotient = -quotient;
	} else {
		quotient = div_u64_rem(dividend, abs(divisor), (u32 *)remainder);
		if (divisor < 0)
			quotient = -quotient;
	}
	return quotient;
}
EXPORT_SYMBOL(div_s64_rem);
#endif

80
/* 64bit divisor, dividend and result. dynamic precision */
R
Roman Zippel 已提交
81 82
#ifndef div64_u64
u64 div64_u64(u64 dividend, u64 divisor)
83
{
R
Roman Zippel 已提交
84
	u32 high, d;
85

S
Stephen Hemminger 已提交
86 87 88
	high = divisor >> 32;
	if (high) {
		unsigned int shift = fls(high);
89 90 91

		d = divisor >> shift;
		dividend >>= shift;
S
Stephen Hemminger 已提交
92 93
	} else
		d = divisor;
94

R
Roman Zippel 已提交
95
	return div_u64(dividend, d);
96
}
R
Roman Zippel 已提交
97 98
EXPORT_SYMBOL(div64_u64);
#endif
99

L
Linus Torvalds 已提交
100
#endif /* BITS_PER_LONG == 32 */
101 102 103 104 105 106 107

/*
 * Iterative div/mod for use when dividend is not expected to be much
 * bigger than divisor.
 */
u32 iter_div_u64_rem(u64 dividend, u32 divisor, u64 *remainder)
{
108
	return __iter_div_u64_rem(dividend, divisor, remainder);
109 110
}
EXPORT_SYMBOL(iter_div_u64_rem);