如何用无溢出的定点算法求多项式?

时间:2016-03-18 15:36:56

标签: c math embedded overflow fixed-point

我想评估一个只有32位整数硬件的实时嵌入式系统上的多项式。出于这个原因,我试图使用定点算术。如何在不对参数施加荒谬限制的情况下避免溢出?

假设我有系数a,b,c,d,我想评估

ax^3 + bx^2 + cx + d

适用于x的特定范围。

假设系数a,b,c,dx的范围可以离线计算,并且可以缩放以生成我用来评估多项式工作的任何方法。

我可以做些什么来避免溢出,但结果中仍然有大约20位的精度? 如果我什么都不做,那么即使是x的小值(如10,000),x ^ 3也是1,000,000,000,000,不适合32位。

举一个例子,假设我想评估多项式

F(x) = ax^3

对于范围为x=<0.0,1.0>的x。我想要F(0.0) = 0.0F(1.0) = 100.0。但我也希望此函数的值在该范围内的10,000点,因此F(0.0001)F(0.0002)等。

如果我希望F(x)的结果始终精确到最接近的整数,我应该如何仅使用32位整数数学来评估F(x)

4 个答案:

答案 0 :(得分:1)

解决ax ^ 3 + bx ^ 2 + cx + d = MAXINT - 1

这给出了不会溢出的最大输入值。

然后相应地缩放输入值。评估多项式,然后反转缩放。

答案 1 :(得分:0)

也许使用某种科学记数法? 1,000,000,000,000是1.0 x 10 ^ 12,因此您可以使用20位在指数之前存储该位,然后剩余的12位可用于额外的精度或指数。

答案 2 :(得分:0)

定义并实施fixed point data types and arithmetic operations

在计算之前,将所有实数转换为定点格式并对其进行操作。

同样让消费者接受定点数据,或将定点数据转换为整数或浮动。

Q值,即缩放因子,是在精度和范围之间进行折衷的设计选择。

#include <stdio.h>
#include <stdint.h>

typedef int32_t Q16;

Q16 floatToQ16(float in)
{
    return in*(1<<16);  
}
float q16ToFloat(Q16 in)
{
    return (float)in/(1<<16);
}
Q16 q16mul(Q16 a, Q16 b)
{
    return (int64_t)a*b>>16;
}
Q16 q16pol(Q16 a, Q16 b, Q16 c, Q16 x)
{
    return q16mul(a, q16mul(q16mul(x, x), x)) 
          + q16mul(b,q16mul(x,x)) 
          + q16mul(c, x); 
}
int main(void) {
    printf("2*20.123^3+3*20.123^2+4*20.123=%f\n",
            q16ToFloat(q16pol(floatToQ16(2.0f), 
                              floatToQ16(3.0f), 
                              floatToQ16(4.0f), 
                              floatToQ16(20.123f))));
    return 0;
}

演示:http://ideone.com/5vVNb8

参考:

GCC API of fixed point arithmetics

N1169 draft, fixed point support in C programming language

答案 3 :(得分:0)

  1. 小数位

    您的示例告诉我们x=<0.0,1.0>步骤至少10000,因此您需要代表min_dx=1.0/10000.0=0.0001

    注意十进制小数部分不容易转换为二进制表示,因此如果您使用10000步骤进行摊位小数位计算,并且作为多个步骤,那么点之间的差异将是非线性的(在0.0001左右振荡)。为了更精确地添加一个或更多位。

    fract_bits=ceil(log2(10000))=14;
    min_dx=1/(2^14)=1/16384=0.00006103515625
    

    使用15小数位来更安全地使用

    min_dx=1/(2^15)=1/32768=0.000030517578125
    
  2. 整数位

    假设 2&#39; os补充已签名的整数算术,我们已离开:

    int_bits=32-fract_bits=32-15=17
    absmax=2^(int_bits-1)=2(16)=16384
    

    因此,如果任何有效<-16384,16383>的多项式表达式的子结果都不超出范围x,那么您可以使用17.15位的定点算术

  3. 多种定点格式

    如果您的多项式表达式的任何子结果超出任何有效<-16384,16383>的范围x,那么您需要使用多种固定格式。对于范围x=<0.0,1.0>,仅当|a|,|b|,|c|,|d|中的任何一个大于absmax/4时,才会出现这种情况。当你声称|result|<=100.0时,这不应该经常发生。

    无论如何,如果x范围为x=<0.0,2.0>,则x^0,x^1,x^2,x^3会有不同的范围,并且可能更容易溢出子结果。在这种情况下,您可以使用较低的fract_bits来获得x的较高幂,每个多项式部分使用不同的固定点格式,最后将所有这些格式计算为单个输出(具有最小数量的小数位) )。

    如果由于精确成本而无法降低fract_bits,那么您需要使用64位(或更多)算术(可以使用32位操作完成)。