我想评估一个只有32位整数硬件的实时嵌入式系统上的多项式。出于这个原因,我试图使用定点算术。如何在不对参数施加荒谬限制的情况下避免溢出?
假设我有系数a,b,c,d
,我想评估
ax^3 + bx^2 + cx + d
适用于x
的特定范围。
假设系数a,b,c,d
和x
的范围可以离线计算,并且可以缩放以生成我用来评估多项式工作的任何方法。
我可以做些什么来避免溢出,但结果中仍然有大约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.0
和F(1.0) = 100.0
。但我也希望此函数的值在该范围内的10,000
点,因此F(0.0001)
,F(0.0002)
等。
如果我希望F(x)
的结果始终精确到最接近的整数,我应该如何仅使用32位整数数学来评估F(x)
?
答案 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;
}
参考:
答案 3 :(得分:0)
小数位
您的示例告诉我们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&#39; os补充和已签名的整数算术,我们已离开:
int_bits=32-fract_bits=32-15=17
absmax=2^(int_bits-1)=2(16)=16384
因此,如果任何有效<-16384,16383>
的多项式表达式的子结果都不超出范围x
,那么您可以使用17.15
位的定点算术
多种定点格式
如果您的多项式表达式的任何子结果超出任何有效<-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位操作完成)。