问题描述
这是我第一次发帖,但如果之前有人问过这个问题,我会提前道歉。
由于极小的值或大于 32 位的结果(在 16 位 MCU 上),我一直在努力研究如何在 C 中实现三阶多项式公式。 我使用不同的值,但作为一个例子,我想计算公式中的“Y”:
Y = ax^3 + bx^2 + cx + d = 0.00000012*(1024^3) + 0.000034*(1024^2) + 0.056*(1024) + 789.10
我需要使用 base32 来为 "a" = 515 获取有意义的值 如果我乘以 1024^3(10 位 ADC),则会得到非常大的 1,073,741,824
我尝试将它们拆分为“术语 A、B、C 和 D”,但由于每个术语的分辨率不同以及我的 16 位 MCU 的限制,我不确定如何将它们合并在一起:
u16_TermA = fnBase32(0.00000012) * AdcMax * AdcMax * AdcMax;
u16_TermB = fnBase24(0.000034) * AdcMax * AdcMax;
u16_TermC = fnBase16(0.056) * AdcMax;
u16_TermD = fnBase04(789.10);
u16_Y = u16_TermA + u16_TermB + u16_TermC + u16_TermD;
/* AdcMax is a variable 0-1024; u16_Y needs to be 16bit */
我很感激有关此事以及如何最好地在 C 中实现这种计算风格的任何帮助。
提前致谢!
解决方法
迈向改进的一步:
ax^3 + bx^2 + cx + d --> ((a*x + b)*x + c)*x + d
它在数值上更稳定,并且倾向于在函数的零附近提供更准确的答案,并且不太可能溢出中间计算。
第二个想法;如果系数保持其在问题中给出的近似相对值,请考虑缩放系数。
N = 1024; // Some power of 2
aa = a*N*N*N
bb = b*N*N
cc = c*N
y = ((aa*x/N + bb)*x/N + cc)*x/N + d
其中 /N
可以通过轮班快速完成。
明智地选择 N
(可能是 2**14 以实现高精度避免 32 位溢出),那么整个代码可能只使用整数数学就可以令人满意地完成。
由于 aa*x/N
只是 a*x*N*N
,我认为 2**16 的比例效果很好。
第三个想法:
除了缩放之外,通常这样的三次方程可以重写为
// alpha is a power of 2
y = (x-root1)*(x-root2)*(x-root3)*scale/alpha
使用方程的根,而不是 a,b,c
。如果方程的起源是某种曲线拟合,这是非常令人满意的。
不幸的是,OP 的方程 roots 有一个复根对。
x1 = -1885.50539
x2 = 801.08603 + i * 1686.95936
x3 = 801.08603 - i * 1686.95936
...在这种情况下代码可以使用
B = -(x1 + x2);
C = x1 * x2;
y = (x-x1)*(x*x + B*x + C)*scale/alpha