固定点算术中的单精度

时间:2017-11-19 00:08:19

标签: c fixed-point taylor-series

对于使用定点算法的泰勒级数计算,我需要最多6个小数位精度。我尝试了不同的定点格式来实现6位小数精度。

例如, 使用s16.15(左移15)格式,我得到2位小数精度.1符号位,16位整数位和15位小数位。

对于s8.23(左移23)格式,最多4个小数位,s4.27(左移27)格式的精度仍然相同。我原以为情况会好转。

以下是泰勒级数展开计算某个点a附近的自然对数。

所以q = x-a,x是1到2之间的用户输入。

<div>
    <label class="required">Langues</label>
    <div id="homebundle_personnel_langues" data-prototype="<div><label for=&quot;homebundle_personnel_langues___name__&quot; class=&quot;required&quot;>__name__label__</label><input type=&quot;text&quot; id=&quot;homebundle_personnel_langues___name__&quot; name=&quot;homebundle_personnel[langues][__name__]&quot; required=&quot;required&quot; value=&quot;New Tag Placeholder&quot; /></div>">
    </div>
</div>

上面提到的代码片段用于C。

结果我需要:0.584963,但我得到的结果是:0.584949

如何实现更高的精确度?

1 个答案:

答案 0 :(得分:2)

OP mul()抛出太多精确度。

(x)>>13)*((y)>>13)会立即丢弃xy的最不重要的13位。

而是执行64位乘法

int32_t mul_better(int32_t x, int32_t y) {
  int64_t mul = x;
  mul *= y;
  mul >>= 27;

  // Code may want to detect overflow here (not shown)

  return (int32_t) mul;
}

更好的是,在丢弃最低有效位之前将产品四舍五入到最近(与均匀相关)。简化是可能的。下面的详细代码,因为它是说明性的。

int32_t mul_better(int32_t x, int32_t y) {
  int64_t mul = x;
  mul *= y;
  int32_t least = mul % ((int32_t)1 << 27);
  mul /= (int32_t)1 << 27;
  int carry = 0;
  if (least >= 0) {
    if (least >  ((int32_t)1 << 26) carry = 1;
    else if ((least ==  ((int32_t)1 << 26)) && (mul % 2)) carry = 1;
  } else {
    if (-least > ((int32_t)1 << 26) carry = -1;
    else if ((-least ==  ((int32_t)1 << 26)) && (mul % 2)) carry = -1;
  }
  return (int32_t) (mul + carry);
}
int32_t mul(int32_t x, int32_t y) {
  int64_t mul = x;
  mul *= y;
  return mul >> 27;
}

void foo(double x) {
  int32_t q = (int32_t) (x * (1 << 27));  // **
  int32_t taylor =
      c0 + mul(q, (c1 - mul(q, (c2  + mul(q,
      (c3 - mul(q, (c4 - mul(q, (c5 + mul(q, c6)))))))))));
  printf("%f %f\n", x,  taylor * 1.0 / (1 << 27));
}

int main(void) {
  foo(0.303609);
}

输出

0.303609 0.584963

**也可以在这里舍入,而不是简单地将FP截断为整数。