如何提高浮点二阶导数计算的准确性?
How to increase accuracy of floating point second derivative calculation?
我编写了一个简单的程序来计算函数的一阶和二阶导数,使用函数指针。我的程序计算出正确答案(或多或少),但对于某些函数,准确度低于我的预期。
这是我要微分的函数:
float f1(float x) {
return (x * x);
}
这些是导数函数,使用中心有限差分法:
// Function for calculating the first derivative.
float first_dx(float (*fx)(float), float x) {
float h = 0.001;
float dfdx;
dfdx = (fx(x + h) - fx(x - h)) / (2 * h);
return dfdx;
}
// Function for calculating the second derivative.
float second_dx(float (*fx)(float), float x) {
float h = 0.001;
float d2fdx2;
d2fdx2 = (fx(x - h) - 2 * fx(x) + fx(x + h)) / (h * h);
return d2fdx2;
}
主要功能:
int main() {
pc.baud(9600);
float x = 2.0;
pc.printf("**** Function Pointers ****\r\n");
pc.printf("Value of f(%f): %f\r\n", x, f1(x));
pc.printf("First derivative: %f\r\n", first_dx(f1, x));
pc.printf("Second derivative: %f\r\n\r\n", second_dx(f1, x));
}
这是程序的输出:
**** Function Pointers ****
Value of f(2.000000): 4.000000
First derivative: 3.999948
Second derivative: 1.430511
我对一阶导数的准确性很满意,但我认为二阶导数太远了(它应该等于 ~2.0)。
我对浮点数的表示方式以及它们有时不准确的原因有了基本的了解,但如何才能使这个二阶导数结果更准确?我可以使用比中心有限差分法更好的方法吗?或者有什么方法可以使用当前方法获得更好的结果?
- 去分析。 ;-) 可能不是“与当前
方法”。
- 使用双精度而不是浮点数。
- 改变 epsilon (h),并以某种方式合并结果。例如,您可以尝试 0.00001、0.000001、0.0000001 并取它们的平均值。事实上,您想要 h 而不是 overflow/underflow 的最小结果。但是不清楚如何检测上溢和下溢
可以通过选择精度更高的类型来提高精度。 float
当前定义为 IEEE-754 32 位数字,精度为 ~7.225
位小数。
您想要的是 64 位对应物:double
具有 ~15.955
位小数精度。
这应该足以满足您的计算需求,但值得一提的是 boosts implementation,它提供了一个 quadruple-precision 浮点数(128 位)。
最后 The GNU Multiple Precision Arithmetic Library 提供具有任意小数位精度的类型。
我编写了一个简单的程序来计算函数的一阶和二阶导数,使用函数指针。我的程序计算出正确答案(或多或少),但对于某些函数,准确度低于我的预期。
这是我要微分的函数:
float f1(float x) {
return (x * x);
}
这些是导数函数,使用中心有限差分法:
// Function for calculating the first derivative.
float first_dx(float (*fx)(float), float x) {
float h = 0.001;
float dfdx;
dfdx = (fx(x + h) - fx(x - h)) / (2 * h);
return dfdx;
}
// Function for calculating the second derivative.
float second_dx(float (*fx)(float), float x) {
float h = 0.001;
float d2fdx2;
d2fdx2 = (fx(x - h) - 2 * fx(x) + fx(x + h)) / (h * h);
return d2fdx2;
}
主要功能:
int main() {
pc.baud(9600);
float x = 2.0;
pc.printf("**** Function Pointers ****\r\n");
pc.printf("Value of f(%f): %f\r\n", x, f1(x));
pc.printf("First derivative: %f\r\n", first_dx(f1, x));
pc.printf("Second derivative: %f\r\n\r\n", second_dx(f1, x));
}
这是程序的输出:
**** Function Pointers ****
Value of f(2.000000): 4.000000
First derivative: 3.999948
Second derivative: 1.430511
我对一阶导数的准确性很满意,但我认为二阶导数太远了(它应该等于 ~2.0)。
我对浮点数的表示方式以及它们有时不准确的原因有了基本的了解,但如何才能使这个二阶导数结果更准确?我可以使用比中心有限差分法更好的方法吗?或者有什么方法可以使用当前方法获得更好的结果?
- 去分析。 ;-) 可能不是“与当前 方法”。
- 使用双精度而不是浮点数。
- 改变 epsilon (h),并以某种方式合并结果。例如,您可以尝试 0.00001、0.000001、0.0000001 并取它们的平均值。事实上,您想要 h 而不是 overflow/underflow 的最小结果。但是不清楚如何检测上溢和下溢
可以通过选择精度更高的类型来提高精度。 float
当前定义为 IEEE-754 32 位数字,精度为 ~7.225
位小数。
您想要的是 64 位对应物:double
具有 ~15.955
位小数精度。
这应该足以满足您的计算需求,但值得一提的是 boosts implementation,它提供了一个 quadruple-precision 浮点数(128 位)。
最后 The GNU Multiple Precision Arithmetic Library 提供具有任意小数位精度的类型。