算法简介
算法实现
这里我使用函数指针方式来保证接口使用的便利性,虽然可变长参数还没做处理,这一点有空再完善吧。。。
#include <iostream>
typedef double(*equaton)(double x, ...);
double square(double x)
{
return x * x;
}
double func1(double x, ...)
{
return cos(x) - square(x)*x;
}
double func2(double x, ...)
{
return -sin(x) - 3 * square(x);
}
double func3(double x, ...)
{
return -cos(x) - 6 * x;
}
bool isbump(double a, double b)
{
for (double i = a; i <= b; i += 1e-2)
if (func3(i) < 0.)
return false;
return true;
}
double newton_method(equaton func, equaton der_func, double a, double b, bool isc, double λ) // isc: 凹 is true; 凸 is false
{
if (func(a)*func(b) >= 0.)
return 0.0;
double x, pre_x;
if (func(a) > 0 && isc)
x = a;
else
x = b;
do
{
pre_x = x;
x -= func(x) / der_func(x);
} while (fabs(func(x)) > λ && fabs(pre_x - x) > λ);
return x;
}
int main()
{
std::cout << "方程的根为:" << newton_method(func1, func2, 0., 1., isbump(0., 1.), 1e-6) << std::endl;
return 0;
}
output:
方程的根为:0.865474
如图:
关于牛顿法开方(或任意次方)算法,强烈推荐看看这个回答:https://www.guokr.com/question/461510/
简单提一下需要注意得地方:求 $ \sqrt{2} $ 时,考虑有 $ x^2 - a = 0 $,即 $ x = \pm \sqrt{a} $,于是 $ x $ 就是迭代公式中的 $ x_i $,$ a = 2 $ 就是我们要求的。回答中给出了求任意次方时的公式,直接套用即可。
开方时的代码实现:
#include <iostream>
int main()
{
double x, pre_x;
x = 1;
pre_x = 9999;
while (fabs(pre_x - x) > 0)
{
pre_x = x;
x = (x + (2 / x)) / 2;
}
std::cout << x << std::endl;
return 0;
}
牛顿法求 $ x^n $ 算法实现(代码有误):
#include <iostream>
double newton_method_power(double a, double b)
{
if (a == 0.)
return 0.;
else if (a == 1. || b == 0.)
return 1.;
else if (b == 1.)
return a;
else if (fabs(b) > 1.)
return 0.; // 当指数|b| > 1 且为整数时,使用快速幂算法;为浮点数时,可以使用微分近似法或泰勒公式求解
else
{
b = 1./b;
double x, pre_x;
x = 1.;
pre_x = 9999.;
while (fabs(pre_x - x) > 0.)
{
pre_x = x;
x = ((b - 1.)*x / b) + (a / (b*newton_method_power(x, b - 1.)));
}
return x;
}
}
int main()
{
std::cout << newton_method_power(8., 1.) << std::endl;
return 0;
}
微分近似公式:
$$ f(x + \Delta x) \approx f(x) + f'(x) \cdot \Delta x $$
例如:
1.求 $ 2^{1.4} $
由 $ f(x) = a^x $,$ f(x + \Delta x) = a^{x + \Delta x} \approx a^{x} + a^{x} ln(a) \cdot \Delta x $
有 $ 2^{1 + 0.4} \approx 2 + 2ln(2) \cdot 0.4 \approx 2.554518... $
而原表达式 $ 2^{1.4} = 2.63902... $
2.求 $ 2^{9} $
利用公式有 $ 2^{10 - 1} = (2^{10})^{(1 - \frac{1}{10})} \approx 2^{10} + 2^{10} ln(2^{10}) \cdot 0.1 \approx 709.783... $
$ 2^9 = 512 $
虽然算得很勉强 2333。。。