我开发嵌入式平台软件,需要一个单词分割算法。问题如下:给定由一系列32位字表示的大整数(可能很多),我们需要将其除以另一个32位字,即计算商(也是大整数)和余数(32位)。当然,如果我在x86上开发此算法,我可以简单地使用GNU MP但这个库对于嵌入式平台来说太大了。此外,我们的处理器没有硬件整数除法器(整数除法在软件中执行)。然而,处理器具有相当快的FPU,因此诀窍是尽可能使用浮点运算。有任何实现方法吗?
#include <gmp.h>
// divides a multi-precision integer a[0..n-1] by a single word c
void div_by_limb(const unsigned *a, unsigned n, unsigned c) {
typedef unsigned long long uint64;
unsigned c_norm = c, sh = 0;
while((c_norm & 0xC0000000) == 0) { // make sure the 2 MSB are set
c_norm <<= 1; sh++;
}
// precompute the inverse of 'c'
double inv1 = 1.0 / (double)c_norm, inv2 = 1.0 / (double)c;
unsigned i, r = 0;
printf("\nquotient: "); // quotient is printed in a loop
for(i = n - 1; (int)i >= 0; i--) { // start from the most significant digit
unsigned u1 = r, u0 = a[i];
union {
struct { unsigned u0, u1; };
uint64 x;
} s = {u0, u1}; // treat [u1, u0] as 64-bit int
// divide a 2-word number [u1, u0] by 'c_norm' using floating-point
unsigned q = floor((double)s.x * inv1), q2;
r = u0 - q * c_norm;
// divide again: this time by 'c'
q2 = floor((double)r * inv2);
q = (q << sh) + q2; // reconstruct the quotient
printf("%x", q);
}
r %= c; // adjust the residue after normalization
printf("; residue: %x\n", r);
}
int main() {
mpz_t z, quo, rem;
mpz_init(z); // this is a dividend
mpz_set_str(z, "9999999999999999999999999999999", 10);
unsigned div = 9; // this is a divisor
div_by_limb((unsigned *)z->_mp_d, mpz_size(z), div);
mpz_init(quo); mpz_init(rem);
mpz_tdiv_qr_ui(quo, rem, z, div); // divide 'z' by 'div'
gmp_printf("compare: Quo: %Zx; Rem %Zx\n", quo, rem);
mpz_clear(quo);
mpz_clear(rem);
mpz_clear(z);
return 1;
}
D
,而是乘以 0x100000000/D
,然后再除以 0x100000000
。后者只是一个字移位,也就是微不足道的。计算乘数有点难,但并不是很难。我相信查找表和牛顿-拉夫逊连续逼近法是硬件设计师的经典选择(通常无法承担完整硬件除法所需的门)。您可以选择在精度和执行时间之间进行权衡。