C中的定点无符号除法

时间:2011-12-14 14:43:19

标签: c division fixed-point

我需要一个算法在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 

2 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:1)

你有一个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