在Matlab中求解具有非常小系数的二次方程

fra*_*a66 0 matlab numerical-methods

我正在使用解决方案公式在matlab中实现一个代码来解决二次方程:

在此输入图像描述

这是代码:

clear all 
format short 
a=1; b=30000000.001; c=1/4; 
rdelta=sqrt(b^2-4*a*c); 
x1=(-b+rdelta)/(2*a);
x2=(-b-rdelta)/(2*a);
fprintf(' Roots of the polynomial %5.3f x^2 + %5.3f x+%5.3f \n',a,b,c)  
fprintf ('x1= %e\n',x1)
fprintf ('x2= %e\n\n',x2)
valor_real_x1= -8.3333e-009;
valor_real_x2= -2.6844e+007;

error_abs_x1 = abs (valor_real_x1-x1);
error_abs_x2 = abs (valor_real_x2-x2);

error_rel_x1 = abs (error_abs_x1/valor_real_x1);
error_rel_x2 = abs (error_abs_x2/valor_real_x2);

fprintf(' absolute_errorx1 = |real value - obtained value| = |%e - %e| = %e \n',valor_real_x1,x1,error_abs_x1)  
fprintf(' absolute_errorx2 = |real value - obtained value| = |%e - %e| = %e \n\n',valor_real_x2,x2,error_abs_x2) 

fprintf(' relative error_x1 = |absolut error / real value| = |%e / %e| = %e \n',error_abs_x1,valor_real_x1,error_rel_x1 ) 
 fprintf(' relative_error_x2 = |absolut error / real value|  = |%e / %e| = %e \n',error_abs_x2,valor_real_x2,error_rel_x2) 
Run Code Online (Sandbox Code Playgroud)

我遇到的问题是它给了我一个精确的解,即对于值a = 1,b = 30000000,001 c = 1/4,根的值是:

Roots of the polynomial 1.000 x^2 + 30000000.001 x+0.250 
 x1= -9.313226e-009
 x2= -3.000000e+007
Run Code Online (Sandbox Code Playgroud)

知道多项式根的确切值是:

x1= -8.3333e-009
x2= -2.6844e+007
Run Code Online (Sandbox Code Playgroud)

这给出了计算的绝对精度和相对精度的以下误差:

 absolute_errorx1 = |real value - obtained value| = |-8.333300e-009 - -9.313226e-009| = 9.799257e-010 
 absolute_errorx2 = |real value - obtained value| = |-2.684400e+007 - -3.000000e+007| = 3.156000e+006 

 relative error_x1 = |absolut error / real value| = |9.799257e-010 / -8.333300e-009| = 1.175916e-001 
 relative_error_x2 = |absolut error / real value|  = |3.156000e+006 / -2.684400e+007| = 1.175682e-001
Run Code Online (Sandbox Code Playgroud)

我的问题是:是否有一种获得二次方程根的最佳方法?即我可以对我的代码进行更改以减少预期解决方案与最终解决方案之间的相对误差?

jmh*_*mhl 7

在这种情况下直接使用二次公式会导致数值精度的大量损失,从而减去两个非常相似的值.这是因为表达

sqrt(b*b - 4*a*c)
Run Code Online (Sandbox Code Playgroud)

与b几乎相同.所以你应该只使用这两个根中的一个,一个不涉及减去两个非常接近的值,另一个根你可以使用(例如)二次方根的乘积为c/a的事实.我会让你填补空白.