# Blatt 5, Aufgabe 2
# Zusammengesetzte Quadraturformeln

import numpy as np

def trapez(N,f,a,b):
    h=(b-a)/N
    Y=0
    for j in range(N):
        xl=  a+j*h
        xr= a+(j+1)*h
        Y+= f(xl) + f(xr)
    Y=(h/2)*Y
    return Y

def simpson(N,f,a,b):
    h=(b-a)/N
    Y=0
    for j in range(N):
        xl=  a+j*h
        xm=  xl+h/2
        xr=  a+(j+1)*h
        Y+= (1/6)*f(xl) + (2/3)*f(xm) +(1/6)*f(xr)
    Y=h*Y
    return Y


# Simpson-Regel mit optimierter Summation
# Hintergrund: Bei Summation in einfacher Scheife kann Information
#              verloren gehen, wie man hier auch praktisch sieht
def simpson2(N,f,a,b):
    h=(b-a)/N
    Y=0
    vl=np.zeros(N)
    vm=np.zeros(N)
    vr=np.zeros(N)
    for j in range(N):
        vl[j]=f(a+j*h)
        vr[j]=f(a+(j+1)*h)
        vm[j]=f(a+j*h+h/2)
    Y=h*sum(1/6*vl+2/3*vm+1/6*vr)
    return Y


def f1(x):
    return np.sin(x)**2

def kurz(x):
# zeige nur 3 signifikante Stellen
    return f"{x:.2e}"


#Intervall
a=-1
b=1

referenzwert_f1=1-.5*np.sin(2)

for N in range(1,100):
    #N=10
    Zt=trapez(N,f1,-1,1)
    Zs=simpson(N,f1,-1,1)
    Z2=simpson2(N,f1,-1,1)
    e_t=abs(Zt-referenzwert_f1)
    e_s=abs(Zt-referenzwert_f1)
    e_2=abs(Z2-referenzwert_f1)
    print("----------------------------------------------------")
    print("N=",N," Approx (Trapez)=",Zt," Fehler |e|=",kurz(e_t), "N^2*|e|=",kurz(N**2*e_t))
    print("N=",N," Approx (Simpson)=",Zs," Fehler |e|=",kurz(e_s), "N^4*|e|=",kurz(N**4*e_s))
    print("N=",N," Approx (Simpson opt)=",Z2," Fehler |e|=",kurz(e_2), "N^4*|e|=",kurz(N**4*e_2))
