3

我需要一种算法来在 C 中进行无符号定点除法。我最多可以使用 32 位字。

我想最小化表示整数部分所需的位数,同时能够使用 [0..15] 范围内的数字。显然,最小位数是 4。问题是我提出的算法只能使用 5 位。因为它将余数与除数进行比较,然后移动余数直到它大于除数,如果除数的最高有效位为 1,那么算法只会移动余数(它永远不会更大)。这是代码:

int divu(int a, int b){
   int pt_int, r, pt_frac=0;
   int i;

   pt_int = ((unsigned) a/b) << BITS_FRAC;
   r = (unsigned) a%b;

   for (i=BITS_FRAC; i>=0; i--){
      if ((unsigned) r < b)
         r <<= 1;
      else{
         r -= b;
        pt_frac += 01 << i;
        r <<= 1;
      }
   }
   return pt_int + pt_frac;
}

如果您确实有解决方案但不想理解代码,请发布它。:)

例子:

我们想将 1.5 除以 2,得到 0.75。假设我们对整数部分使用 4 位,对小数部分使用 28 位。所以我们的数字是十六进制的:

1.5:    0x18000000
2:      0x20000000
result: 0x0c000000 
4

2 回答 2

3

你有一个 4.28 的定点数,你想除以一个 4.28 的数。您可以通过从分母中减去分子的精度来找到除法后的精度,因此直接除法将给出 4.28 - 4.28 = 0 - 没有有效位。显然这行不通。

     1.5  [4.28] 0x18000000 
   / 2.0  [4.28] 0x20000000 
   =  0?  [0.00] 0x00000000

理想的方法是将分子提升到 8.56(乘以 2^28),然后进行 64 位除法:

                     .   .   .   .
     1.5  [8.56] 0x180000000000000
   / 2.0  [4.28]        0x20000000 
   = 0.75 [4.28]        0x0c000000

如果您真的不能使用 64 位数字,那么您唯一的选择就是减少分母。例如,您可以通过除以 2^14 来使用一半的精度

     1.5  [4.28] 0x18000000 
   / 2.0  [2.14]     0x8000
   = 0.75 [2.14]     0x3000

然后,您可以将结果乘以相同的因子以返回 4.28 数字: 0x3000 *(1<<14) = 0x0c000000

这样你确实会失去一些精度,但如果不使用更大的分子,这是不可避免的。例如 5.0/3.0 = 1.66667 = 0x1AAAAAA [4.28],但是
((5.0<<28)/(3<<14))<<14 = 0x1AAA8000 [4.28] = 1.66662

于 2011-12-14T19:38:17.873 回答
1

正如此处所指出的(示例:将整数乘以常数的倒数),您可以通过乘以倒数来重新实现除法。之后,您应该能够用 4 位表示整数部分。

于 2011-12-14T15:30:44.237 回答