C 如何使用定点算法计算多项式而不产生溢出?

C 如何使用定点算法计算多项式而不产生溢出?,c,math,embedded,overflow,fixed-point,C,Math,Embedded,Overflow,Fixed Point,我想在只有32位整数硬件的实时嵌入式系统上计算多项式。因此,我尝试使用定点算法。我如何避免溢出而不对参数施加荒谬的限制 假设我有系数a,b,c,d,我想计算 ax^3 + bx^2 + cx + d 对于特定范围的x 假设系数a、b、c、d和x的范围可以离线计算,并且可以进行缩放,以使我使用的任何方法都可以评估多项式的工作 我能做些什么来避免溢出,但结果仍有大约20位的精度? 如果我什么也不做,那么即使对于x(比如10000)的小值,x^3也是10000000000,这不适合32位 举个例子,

我想在只有32位整数硬件的实时嵌入式系统上计算多项式。因此,我尝试使用定点算法。我如何避免溢出而不对参数施加荒谬的限制

假设我有系数
a,b,c,d
,我想计算

ax^3 + bx^2 + cx + d
对于特定范围的
x

假设系数
a、b、c、d
x
的范围可以离线计算,并且可以进行缩放,以使我使用的任何方法都可以评估多项式的工作

我能做些什么来避免溢出,但结果仍有大约20位的精度? 如果我什么也不做,那么即使对于x(比如10000)的小值,x^3也是10000000000,这不适合32位

举个例子,假设我要计算多项式

F(x) = ax^3
对于范围
x=
中的x。我想要
F(0.0)=0.0
F(1.0)=100.0
。但是我也希望这个函数的值在这个范围内的
10000
点,所以
F(0.0001)
F(0.0002)
等等


如果我希望F(x)的结果总是精确到最接近的整数,我应该如何仅使用32位整数数学计算F(x)?

可能使用某种科学符号?10000000000是1.0 x 10^12,因此可以使用20位存储指数之前的位,然后剩余的12位可以用于额外精度或指数。

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

这将提供不会溢出的最大输入值

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

定义并实现

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

还可以使使用者接受定点数据,或将定点数据转换为整数或浮点

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;
}
#包括
#包括
typedef int32_t Q16;
Q16浮动至Q16(浮动)
{
返回*(1)
  • 小数位数

    您的示例告诉我们,
    x=
    至少包含
    10000
    步骤,因此您需要表示
    min\u dx=1.0/10000.0=0.0001

    注意,十进制小数部分不容易转换为二进制表示,因此,如果您使用
    10000
    步骤进行booth分数位数计算,并且作为一系列步骤,则点之间的差值将是非线性的(在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'os补码有符号整数算术我们剩下:

    int_bits=32-fract_bits=32-15=17
    absmax=2^(int_bits-1)=2(16)=16384
    
    因此,如果多项式表达式的子结果没有超出任何有效
    x
    范围,则可以使用
    17.15
    位的定点算术

  • 多种定点格式


    如果多项式表达式的任何子结果对于任何有效的
    x
    都超出了范围
    ,则需要使用多个固定格式。对于范围
    x=
    ,只有当
    |a |、|b |、|c |、| d |
    中的任何一个大于
    absmax/4
    时,才会发生这种情况。正如您所声称的
    |结果|您需要定义“x的特定范围”,即最大、最小和所需的分辨率。可能的重复我不太确定您是否需要定点算法,也许您是指长数学?需要定义
    a、b、c、d
    的可能值范围。通常您将其评估为
    c0+x*(c1+x*(c2+x*c3))
    。对于具有
    q=1.0
    的定点运算,请使用
    c0+(x*(c1+(x*(c2+(x*c3)/q))/q
    。临时值总是双宽的;如何实现这一点取决于体系结构。(许多处理器支持32+32=64位乘法,即使它们不支持64位运算。)如果您的体系结构具有允许定点或模拟浮点类型的快速融合乘法相加功能的功能,则使用
    fma(x,fmaf(x,fmaf(x,c3,c2),c0)
    fma(a,b,c)=a*b+c
    )当某些系数为负数或
    x
    为负数时,单个项可能溢出。这假设任何值或中间结果的大小都不能大于2^15或小于2^-16。当我需要超过这些限制时,会发生什么情况?@Filipp Decrease
    Q
    。太好了!现在我的限制为2^16到2^-15,剩下一个等式我的问题很严重。如果你需要浮点,那么你肯定需要浮点。定点只能提供一个固定的范围和精度。我说选择
    Q
    是一个设计决定,需要定制适合特定精度和范围要求的工作。然而,在实践中,Q值通常是动态的。如果你能如果对所需的
    Q
    进行良好的估计(例如,通过查找位模式中最重要的1的位置来估计log2(x)),则可以使用更灵活/自适应的Q格式。