卡丹公式和盛金公式推导——求解一元三次方程
看 $AcWing$ 上好像还没有关于盛金公式解三次方程的分享,今天来写一篇~
在做洛谷P1024一元三次方程求解这道题的时候,发现题解里有关于盛金公式的介绍,于是自己也去按卡丹公式(Cardano formula)推导了一下~
题目介绍
有形如:$ax^3+bx^2+cx+d=0$ 这样的一个一元三次方程。给出该方程中各项的系数($a,b,c,d$ 均为实数),并约定该方程存在三个不同实根(根的范围在 $-100$ 至 $100$ 之间),且根与根之差的绝对值 $\ge 1$ 。要求由小到大依次在同一行输出这三个实根(根与根之间留有空格),并精确到小数点后 $2$ 位。
卡丹公式介绍
有三元一次方程$$ax^3+bx^2+cx+d=0$$
设函数$$f(x)=ax^3+bx^2+cx+d$$
可以求导得到$$f^\prime (x)=3ax^2+2bx+c$$
该二次函数顶点横坐标为$$x=-\frac{b}{3a}$$
记为 $\lambda$ ,令 $x-\lambda=y$ ,有$$f(x)=a\left(y-\frac{a}{3b}\right)^3+b\left(y-\frac{a}{3b}\right)^2+c\left(y-\frac{a}{3b}\right)+d$$
令 $f(x)=0$ ,化简后二次项可消去,得到$$y^3-py+q=0$$其中
$$
\begin{align}
p&=\frac{b^2-3ac}{3a^2}\\\\
q&=\frac{2b^3-9abc+27a^2d}{27a^3}
\end{align}
$$
引入完全立方公式$$(u+v)^3=u^3+3u^2v+3uv^2+v^3$$变形得到$$(u+v)^3-3uv(u+v)-(u^3+v^3)=0$$
记 $y=u+v$ ,有$$y^3-3uvy-(u^3+v^3)=0$$发现该方程与 $y^3-py+q=0$ 相似,于是设$$p=3uv,q=-(u^3+v^3)$$
得到$$\begin{align}
u&=\sqrt[3]{-\frac{q}{2}+\sqrt{\left(\frac{q}{2}\right)^2-\left(\frac{p}{3}\right)^3}}\\\\
v&=\sqrt[3]{-\frac{q}{2}-\sqrt{\left(\frac{q}{2}\right)^2-\left(\frac{p}{3}\right)^3}}
\end{align}$$
对于方程$$x^3=\lambda$$其三个解分别为$$x_1=\sqrt[3]{\lambda},x_2=\omega\sqrt[3]{\lambda},x_3=\omega^2\sqrt[3]{\lambda}$$其中 $\omega=\frac{-1+\sqrt{3}i}{2},\omega^2=\frac{-1-\sqrt{3}i}{2}$
由此可知,三次方程的判别式为$$\Delta = \left(\frac{q}{2}\right)^2-\left(\frac{p}{3}\right)^3$$
于是,卡丹判别法为:
当 $\Delta > 0$ 时,方程有一个实根和一对共轭虚根;
当 $\Delta = 0$ 时,方程有三个实根,其中有一个两重根;
当 $\Delta < 0$ 时,方程有三个不相等的实根。
三次方程求根公式过于冗长,可通过上述推导得出,故不再赘述。
盛金公式介绍
在推导卡丹判别式的时候,我们有
$$
\begin{align}
p&=\frac{b^2-3ac}{3a^2}\\\\
q&=\frac{2b^3-9abc+27a^2d}{27a^3}
\end{align}
$$
观察 $p$ ,不妨令 $A=b^2-3ac$ ,则可得到
$$\begin{align}
p&=\frac{A}{3a^2}\\\\
q&=\frac{2Ab-3a(bc-9ad)}{27a^3}
\end{align}
$$
此时观察 $q$ ,不妨令 $B=bc-9ad$ ,则可二次简化 $q$ $$q=\frac{2Ab-3aB}{27a^3}$$
于是,当 $A=B=0$ 时, $p=q=0$ ,有三重根,得到盛金公式1 $$x_1=x_2=x_3=-\frac{b}{3a}=-\frac{c}{b}=-\frac{3d}{c}$$
当 $A \ne 0$ 时,从判别式 $\Delta = (\frac{q}{2})^2-(\frac{p}{3})^3$ 入手进行推导。
将 $A$ 和 $B$ 代入并化简得 $$\Delta=\frac{B^2-4A(c^2-3bd)}{324a^4}$$
联系二次方程的求根公式,不妨设 $C=c^2-3bd$ ,则得到盛金总判别式 $$\Delta=\left(\frac{q}{2}\right)^2-\left(\frac{p}{3}\right)^3=\frac{B^2-4AC}{(18a^2)^2}$$
为与总判别式区分,记 $$\delta=B^2-4ac$$为 盛金判别式
对于卡丹公式推导过程中的$$\begin{align}
u&=\sqrt[3]{-\frac{q}{2}+\sqrt{\left(\frac{q}{2}\right)^2-\left(\frac{p}{3}\right)^3}}\\\\
v&=\sqrt[3]{-\frac{q}{2}-\sqrt{\left(\frac{q}{2}\right)^2-\left(\frac{p}{3}\right)^3}}
\end{align}$$
我们可以用上面的简单代换简化$$\begin{align}
u&=-\frac{1}{3a}\sqrt[3]{Ab+\frac{3a(-B-\sqrt{\delta})}{2}}\\\\
v&=-\frac{1}{3a}\sqrt[3]{Ab+\frac{3a(-B+\sqrt{\delta})}{2}}
\end{align}$$
将根式下的内容提出,记作$$\begin{align}
Y_1&=Ab+\frac{3a(-B-\sqrt{\delta})}{2}\\\\
Y_2&=Ab+\frac{3a(-B+\sqrt{\delta})}{2}
\end{align}$$
回代自然也有$$\begin{align}
u&=-\frac{\sqrt[3]{Y_1}}{3a}\\\\
v&=-\frac{\sqrt[3]{Y_2}}{3a}
\end{align}$$
综合得到 $y$ 的通解$$\begin{align}
y_1&=-\frac{\sqrt[3]{Y_1}+\sqrt[3]{Y_2}}{3a}\\\\
y_2&=\frac{(\sqrt[3]{Y_1}+\sqrt[3]{Y_2})+\sqrt{3}(\sqrt[3]{Y_1}-\sqrt[3]{Y_2})i}{-6a}\\\\
y_3&=\frac{(\sqrt[3]{Y_1}+\sqrt[3]{Y_2})-\sqrt{3}(\sqrt[3]{Y_1}-\sqrt[3]{Y_2})i}{-6a}
\end{align}$$
同样可以得到 $x$的通解$$\begin{align}
x_1&=\frac{-b-(\sqrt[3]{Y_1}+\sqrt[3]{Y_2})}{3a}\\\\
x_2&=\frac{-2b+(\sqrt[3]{Y_1}+\sqrt[3]{Y_2})+\sqrt{3}(\sqrt[3]{Y_1}-\sqrt[3]{Y_2})i}{6a}\\\\
x_3&=\frac{-2b+(\sqrt[3]{Y_1}+\sqrt[3]{Y_2})-\sqrt{3}(\sqrt[3]{Y_1}-\sqrt[3]{Y_2})i}{6a}
\end{align}$$
以上六式即为 盛金公式2 ,前提是 $\delta=B^2-4AC>0$ 。显然,当 $\delta>0$ 时,方程有一个实根和一对共轭虚根。
当 $\delta=0$ 时,以盛金公式2求解,有
$$x_1=\frac{-b-2\sqrt[3]{Y}}{3a},x_2=x_3=\frac{-b+\sqrt[3]{Y}}{3a}$$其中$$Y=\frac{2Ab-3aB}{2}$$联系 $\delta=0$ ,有$$(2Ab-3aB)^2=4A^3$$显然,此时 $A>0$ ,同乘以 $Y$ 并变形得到 $$Y=\frac{(2Ab-3aB)^3}{8A^3}$$代入 $x$ 此时的特解得到$$x_1=-\frac{b}{a}+\frac{B}{A},x_2=x_3=-\frac{B}{2A}$$此即为盛金公式3。
当 $\delta<0$ 时,有$$\begin{align}
Y_1&=Ab+\frac{3a(-B-\sqrt{-\delta})}{2}i\\\\
Y_2&=Ab+\frac{3a(-B+\sqrt{-\delta})}{2}i
\end{align}$$
不妨设 $a>0$ ,有$$\begin{align}
Y_1&=Ab+\frac{3a(-B-\sqrt{4A^3-(2Ab-3aB)^2})}{2}i\\\\
Y_2&=Ab+\frac{3a(-B+\sqrt{4A^3-(2Ab-3aB)^2})}{2}i
\end{align}$$
利用复数开方法则,有$$
\sqrt[3]{Y_1}=
\left\\{\begin{aligned}
& \sqrt{A}\left(\cos\frac{\theta}{3}+i\sin\frac{\theta}{3}\right) \\\
& \sqrt{A}\left[\cos\left(\frac{\theta}{3}+\frac{2\pi}{3}\right)+i\sin\left(\frac{\theta}{3}+\frac{2\pi}{3}\right)\right] \\\
& \sqrt{A}\left[\cos\left(\frac{\theta}{3}+\frac{2\pi}{3}\right)+i\sin\left(\frac{\theta}{3}-\frac{2\pi}{3}\right)\right] \\\
\end{aligned}
\right.
$$
$$
\sqrt[3]{Y_2}=
\left\\{\begin{aligned}
& \sqrt{A}\left(\cos\frac{\theta}{3}-i\sin\frac{\theta}{3}\right) \\\
& \sqrt{A}\left[\cos\left(\frac{\theta}{3}+\frac{2\pi}{3}\right)-i\sin\left(\frac{\theta}{3}+\frac{2\pi}{3}\right)\right] \\\
& \sqrt{A}\left[\cos\left(\frac{\theta}{3}+\frac{2\pi}{3}\right)-i\sin\left(\frac{\theta}{3}-\frac{2\pi}{3}\right)\right] \\\
\end{aligned}
\right.
$$
其中 $$\theta=\arccos\left(\frac{2Ab-3aB}{2\sqrt{A^3}}\right)$$
有约束条件$$\sqrt[3]{Y_1}\cdot\sqrt[2]{Y_2}=A$$
选取合适的 $u$ 和 $v$ 代入盛金公式2,得到
$$
\left\\{\begin{aligned}
x_1&=\frac{-b-2\sqrt{A}\cos\frac{\theta}{3}}{3a} \\\
x_2&=\frac{-b+\sqrt{A}\left(\cos\frac{\theta}{3}+\sqrt{3}\sin\frac{\theta}{3}\right)}{3a} \\\
x_2&=\frac{-b+\sqrt{A}\left(\cos\frac{\theta}{3}-\sqrt{3}\sin\frac{\theta}{3}\right)}{3a} \\\
\end{aligned}
\right.
$$
此即为 盛金公式4。当然为了形式上更加规范,也可用差角公式进行改写
$$
\left\\{\begin{aligned}
x_1&=\frac{-b-2\sqrt{A}\cos\frac{\theta}{3}}{3a} \\\
x_2&=\frac{-b-2\sqrt{A}\left(\frac{\theta}{3}+\frac{2\pi}{3}\right)}{3a} \\\
x_2&=\frac{-b-2\sqrt{A}\left(\frac{\theta}{3}-\frac{2\pi}{3}\right)}{3a} \\\
\end{aligned}
\right.
$$
以上推导盛金公式4的过程是基于 $a>0$ 的假设的,当 $a<0$ 时推导过程完全一致,只需互换 $Y_1$ 和 $Y_2$ 的位置即可。
至此,盛金公式推导完毕。
题目解答
当然可以用二分来做出三次方程的解,提供题解如下:
#include<bits/stdc++.h>
using namespace std;
double a, b, c, d;
double fc(double x)
{
return a * x * x * x + b * x * x + c * x + d;
}
int main()
{
double l, r, m, x1, x2;
int s = 0, i;
scanf("%lf%lf%lf%lf", &a, &b, &c, &d);
// 枚举互相不重叠的每一个长度为1的区间,在区间内进行二分查找
for (i = -100; i < 100;i++)
{
l = i;
r = i + 1;
x1 = fc(l);
x2 = fc(r);
if(!x1)
{
printf("%.2lf ", l);
s ++;
} //判断左端点,是零点直接输出。
//不能判断右端点,会重复。
if(x1 * x2 < 0) //区间内有根。
{
while(r - l >= 0.001) //二分控制精度。
{
m = (l + r) / 2; //middle
if(fc(m) * fc(r) <= 0)
l = m;
else
r = m; //计算中点处函数值缩小区间。
}
printf("%.2lf ", r);
//输出右端点。
s++;
}
if (s == 3)
break;
//找到三个就退出大概会省一点时间
}
return 0;
}
用盛金公式做就更简单啦
#include <bits/stdc++.h>
using namespace std;
int main()
{
double a, b, c, d;
double as, bs, t, si;
double x1, x2, x3;
cin >> a >> b >> c >> d;
as = b * b - 3 * a * c;
bs = b * c - 9 * a * d;
t = (2 * as * b - 3 * a * bs) / (2 * sqrt(as * as * as));
si = acos(t);
x1 = (-b - 2 * sqrt(as) * cos(si / 3)) / (3 * a);
x2 = (-b + sqrt(as) * (cos(si / 3) + sqrt(3) * sin(si / 3))) / (3 * a);
x3 = (-b + sqrt(as) * (cos(si / 3) - sqrt(3) * sin(si / 3))) / (3 * a);
cout << fixed << setprecision(2) << x1 << " ";
cout << fixed << setprecision(2) << x3 << " ";
cout << fixed << setprecision(2) << x2 << " ";
return 0;
}
$$The\ End~$$
感觉所以盛金公式和卡丹公式是一个东西,式子变形一下就能互相得出结果了
大佬太强了 我直接%%%%%
神犇明明是你🥺