- 了解linux 64位除法
1.介绍
The GCC C compiler generates code that calls functions in the libgcc library to implement the / and % operations with 64-bit operands on 32-bit CPUs. However, the Linux kernel is not linked against the libgcc library, so such code will fail to link when building code for a 32-bit Linux kernel. (When building an external kernel module, the problem may not be apparent until you try and dynamically load the module into the running kernel.)
Originally, the Linux kernel only had the do_div(n,base) macro defined by #include <asm/div64.h>. The usage of this macro is unusual because it modifies its first argument in place to become the quotient resulting from the division, and yields (returns) the remainder from the division as its result. This was done for code efficiency reasons but is a bit of a pain to use. Also, it only supports division of a 64-bit unsigned dividend by a 32-bit divisor.
Linux kernel version 2.6.22 introduced the #include <linux/math64.h> header, which defines a set of functions which is more comprehensive than the old do_div(n,base) macro and is easier to use because they behave like normal C functions.
The functions declared by #include <linux/math64.h> for 64-bit division are listed below. Except where indicated, all of these have been available since kernel version 2.6.26.
- u64 div_u64(u64 dividend, u32 divisor) — unsigned division of 64-bit dividend by 32-bit divisor.
- s64 div_s64(s64 dividend, s32 divisor) — signed division of 64-bit dividend by 32-bit divisor.
- u64 div_u64_rem(u64 dividend, u32 divisor, u32 *remainder) — unsigned division of 64-bit dividend by 32-bit divisor with remainder.
- s64 div_s64_rem(s64 dividend, s32 divisor, s32 *remainder) — signed division of 64-bit dividend by 32-bit divisor with remainder.
- u64 div64_u64(u64 dividend, u64 divisor) — unsigned division of 64-bit dividend by 64-bit divisor.
- s64 div64_s64(s64 dividend, s64 divisor) — (since 2.6.37) signed division of 64-bit dividend by 64-bit divisor.
- u64 div64_u64_rem(u64 dividend, u64 divisor, u64 *remainder) — (since 3.12.0) unsigned division of 64-bit dividend by 64-bit divisor with remainder.
- s64 div64_s64_rem(s64 dividend, s64 divisor, s64 *remainder) — (does not exist yet as of 4.18-rc8) signed division of 64-bit dividend by 64-bit divisor with remainder.
- div64_long(x,y) — (since 3.4.0) macro to do signed division of a 64-bit dividend by a long int divisor (which is 32-bit or 64 bit, depending on the architecture).
- div64_ul(x,y) — (since 3.10.0) macro to do unsigned division of a 64-bit dividend by an unsigned long int divisor (which is 32-bit or 64-bit, depending on the architecture).
- u32 iter_div_u64_rem(u64 dividend, u32 divisor, u64 *remainder) — unsigned division of 64-bit division by 32-bit divisor by repeated subtraction of divisor from dividend, with remainder (may be faster than regular division if the dividend is not expected to be much bigger than the divisor).
2.do_div funciton
25 # define do_div(n,base) ({ \
26 uint32_t __base = (base); \
27 uint32_t __rem; \
28 __rem = ((uint64_t)(n)) % __base; \
29 (n) = ((uint64_t)(n)) / __base; \
30 __rem; \
31 })
64 bit division 结果保存在n中;余数保存在返回结果中。do_div得到的结果是余数,而真正的n/base的结果,是用n来保存的。 因为do_div将商保存在被除数中,把原值覆盖了,所以实际运用时要用临时变量保存被除数。
3.DIV_ROUND_CLOSEST function
96 #define DIV_ROUND_CLOSEST(x, divisor)( \
97 { \
98 typeof(x) __x = x; \
99 typeof(divisor) __d = divisor; \
100 (((typeof(x))-1) > 0 || \
101 ((typeof(divisor))-1) > 0 || (__x) > 0) ? \
102 (((__x) + ((__d) / 2)) / (__d)) : \
103 (((__x) - ((__d) / 2)) / (__d)); \
104 } \
105 )
该函数主要进行四舍五入计算使用。例如:3/2=1.5,计算机中的整数运算结果为 3/2=1,经过DIV_ROUND_CLOSEST函数四舍五入运算后,3/2=2。