计算方法——非线性方程的解法(二分法、试值法、迭代法、牛顿法)

非线性方程的解法(python)

  • 二分法
  • 试值法
  • 不动点迭代法
  • 牛顿法

二分法

1.简介
连续函数f(x)在根两边会变号,如果[a,b]区间有根,则f(a)*f(b)<0,令S1: e=(a+b)/2,If f (e)=0,e是根,end;ElseIf f(a)*f(e)<0,[a, e]中有根,Set b=e, go to S1;Else,[e, b]中有根,Set a=e, go to S1

2.结束二分法的条件
①有一个中点值使得f(x)=0;
②区间足够小时,小于一个提前设定的值delta时,即(a-b)

3.题目
【问题描述】如果在240个月内每月付款300美元,使用二分法在利率区间[a,b] 内,求能够满足在这240个月之后使本金和利息的总值达到50万美元的利率值(年利率为I,则月利率为 I/12),精确到小数点后第d位。

【输入形式】在屏幕上输入3个数,依次为利率区间左端点值a、右端点值b和精确到小数点后d位。各数间都以一个空格分隔。测试用例的输入满足:b>a>0, 1<=d<=8, d为正整数。

【输出形式】输出两行数据,第一行为迭代次数,第二行为求得的利率,保留d位小数。

【样例输入】

0.15 0.16 8

【样例输出】

20

0.15753931

【样例说明】输入:左端点值为0.15,右端点值为0.16,求得的利率精确到小数点后8位。输出:表示经 20 次迭代,求得满足条件的利率值为 0.15753931。

import math
#输入并用空格分开
Enter=input()
Num=Enter.split(" ")
#字符型转换成数字
a=float(Num[0])
b=float(Num[1])
n=int(Num[2])
#总金额
sum=0.0
#用于后面计算迭代次数
temp1=a
temp2=b
#二分法
while abs(sum-500000.0)>0.1**n:
    c=(a+b)/2
    sum = 3600 / c * ((1 + c / 12) ** 240 - 1)
    suma=3600/a*((1+a/12)**240-1)
    sumb=3600/b*((1+b/12)**240-1)
    if (sum-500000)*(suma-500000)>0:
        a=c
    else:
        b=c
#迭代次数
print(int((math.log(temp2-temp1)-math.log(0.1**n))/math.log(2))+1)
#利率结果
print(round(c,n))

试值法

1.简介
假设f(a)*f(b)<0,求得经过点(a, f(a))和(b, f(b)) 的割线L与x轴的交点(e, 0),该点更接近于根。
其中 e=b-(f(b)(b-a))/(f(b)-f(a))

2.结束试值法的条件
①最大循环次数
②根所在区间宽度
③f(e)

3.题目(同上)
【问题描述】如果在240个月内每月付款300美元,使用试值法在利率区间[a,b] 内,求能够满足在这240个月之后使本金和利息的总值达到50万美元(允许误差范围为0.0001美元)的利率值,精确到小数点后第d位。

【输入形式】在屏幕上输入3个数,依次为利率区间左端点值a、右端点值b和精确到小数点后d位。各数间都以一个空格分隔。测试用例的输入满足:b>a>0, 1<=d<=8, d为正整数。

【输出形式】输出两行数据,第一行为迭代次数,第二行为求得的利率,保留d位小数。

【样例输入】

0.15 0.16 8

【样例输出】

5

0.15753931

【样例说明】输入:左端点值为0.15,右端点值为0.16,求得的利率精确到小数点后8位。输出:表示经5次迭代,求得满足条件的利率值为0.15753931。

【评分标准】根据输入得到的输出准确

import math
#输入并用空格分开
Enter=input()
Num=Enter.split(" ")
#字符型转换成数字
a=float(Num[0])
b=float(Num[1])
n=int(Num[2])
c=1
#记录迭代次数
i=0
#精度
delta = 0.5 * 10 **(-n)
#公式
def formular(temp):
    result=3600 / temp * ((1 + temp / 12) ** 240 - 1)-500000
    return result

#试值法
while abs(formular(c))>0.1**n:
    c=b-(formular(b)*(b-a))/(formular(b)-formular(a))
    if abs(formular(c))<0.0001:
        break
    elif (delta > b-a):
        break
    elif formular(a)*formular(c)<0:
        b=c
        i=i+1
    else:
        a=c
        i=i+1

#迭代次数
print(i)
#利率结果
print(round(c,n))

不动点迭代法

1.简介
设法把方程f(x)=0转化为:x=g(x),并构造迭代公式:pn+1=g(pn) ,其中n=0, 1,… 在有根区间[a, b]上取一点p0作为方程f(x)=0的初始近似根,代入上式,得到p1=g(p0),p2=g(p1), …, 从而得到序列{pn},如果序列的极限P存在,则P是函数g(x)的不动点,也是方程f(x)=0的根。

2.重点
①如何选取一个收敛的g(x)
②如何选取迭代初始点

3.结束迭代法的条件
p(n)-p(n-1)的绝对值小于一个预定的值(精度)

4.题目
【问题描述】在[a,b]区间内寻找方程x**5-2*x-1=0的根的初始近似值位置,确定不动点迭代的初始点(可能有多个),然后使用不动点迭代法求方程的根(可能有多个根)。前后两次迭代的差的绝对值小于delta后停止迭代。

【输入形式】在屏幕上输入3个数,依次为区间左端点值a、右端点值b和所求根的精度值。各数间都以一个空格分隔。根据输入的所求根的精度值可求得delta.

【输出形式】每一行输出一个根(精确到小数点后3位)

【样例1输入】

-1.2 1.5 3

【样例1输出】

-1.000

-0.519

1.291

【样例1说明】输入:左端点a值为-1.2,右端点b值为1.5,前后两次迭代的差的绝对值小于delta=10**(-3)后停止迭代。输出:从小到大顺序输出三个根的值。

【评分标准】根据输入得到的输出准确

import math
#输入并用空格分开
Enter=input()
Num=Enter.split(" ")
#字符型转换成数字
a=float(Num[0])
b=float(Num[1])
deltaa=int(Num[2])
#精度
delta=10**(-deltaa)
#迭代公式一
def pan(A):
    A=2*A+1
    if A < 0:
         return -math.pow(math.fabs(A), 0.2)
    else:
         return math.pow(A, 0.2)
#迭代公式二
def duan(B):
        return (math.pow(B,5)-1)/2
#获得第一个不动点
p1=(b-a)/8/2+a
p2=pan(p1)
while math.fabs(p2-p1)>delta:
    p1=p2
    p2=pan(p1)
result1=p2
#获得第二个不动点
p1=(b-a)/8*3+a
p2=duan(p1)
while math.fabs(p2-p1)>delta:
    p1=p2
    p2=duan(p1)

result2=p2
#获得第三个不动点
p1=(b-a)/8*7.5+a
p2=pan(p1)
while math.fabs(p2-p1)>delta:
    p1=p2
    p2=pan(p1)
result3=p2
print('%.3f'%result1)
print('%.3f'%result2)
print('%.3f'%result3)
#这个题不太行,必须将区间分成八等份,然后分别取区间的第0.5份,第3份和第7.5份才能和测试数据完全匹配,并且我也不知道为什么要这么分,就很奇怪。

牛顿法

1.简介
p为方程f(x)=0的根,设初始值p0在p的附近,过函数曲线上的点(p0,f(p0))的切线L与x轴的焦点为p1,设f属于[a,b],且存在数p属于[a,b],满足f(p)=0,f的导数在p点不为0,则存在一个数t>0,对任意初始近似值p0属于[p-t,p+t],使得由下列迭代公式得到的序列pk收敛到p:
pk=g(p(k-1))=p(k-1)-f(p(k-1))/f’(p(k-1))
2.结束迭代的条件
①前后两次迭代的差小于某一设定的精度
②与渐进误差常数有关
③与所给函数的函数值精度有关
3.题目
【题目简述】牛顿法解投射体问题(非线性方程求解)

【问题描述】在考虑空气阻力情况下,求解投射体撞击地面时经过的时间和水平飞行行程,其中:y=f(t)=9600*(1-e**(-t/15.0)) - 480t;x=r(t)=2400(1-e**(-t/15.0))。

【输入形式】在屏幕上输入3个数,分别表示起始值、前后两次迭代的差的绝对值精度和f(t)函数值的精度。各数间都以一个空格分隔。

【输出形式】第一行输出投射体撞击地面时经过的时间,第二行输出水平飞行行程,精确到小数点后5位。

【样例1输入】

8 1 1

【样例1输出】

9.08955

1090.69211

【样例1说明】输入:起始值为8、前后两次迭代的差的绝对值精度为0.1和f(t)函数值的精度为0.1。输出:第一行输出投射体撞击地面时经过的时间为9.08955秒,第二行输出水平飞行行程为1090.69211ft。

import math
#公式
def f(p):
    p=9600*(1-math.e**(-p/15.0)) - 480*p
    return p
def f_der(p):
    p=640*(math.e**(-p/15.0))-480
    return p
def x(p):
    p=2400*(1-math.e**(-p/15.0))
    return p
#输入并用空格分开
Enter=input()
Num=Enter.split(" ")
#字符型转换成数字
p0=float(Num[0])
delta=int(Num[1])
eps=int(Num[2])
p1=p0-f(p0)/f_der(p0)
#精度
delta=0.1**delta
eps=0.1**eps
err=math.fabs(math.fabs(p0)-math.fabs(p1))
relerr=2*err/(math.fabs(p1)+delta)
y=f(p0)
#迭代
while((err>delta)and(relerr>delta)and(math.fabs(y)>eps)):
    p1 = p0 - f(p0) / f_der(p0)
    err = math.fabs(math.fabs(p0) - math.fabs(p1))
    relerr = 2 * err / (math.fabs(p1) + delta)
    p0=p1
    y = f(p0)
#飞行行程
x=x(p0)
print('%.5f'%p0)
print('%.5f'%x)

你可能感兴趣的:(python,计算方法)