// IntegralRumberg
/*
------------------------------------------------------
作者   : Black Ghost
日期   : 2018-12-12
版本   : 0.0.0
------------------------------------------------------
    Rumberg(龙贝格)求积分公式
理论：
    对于积分
    b
    |f(x)dx
    a

          b-a
    T1 = -----(f(a)+f(b))
           2

           1       b-a N              b-a
    T2N = ---TN + -----Sum f(a+(2j-1)------)
           2       2N  j=1             2N
    N=2^(k-1), k=1,2,3,...

                1            4T2N-TN
    SN = T2N + ---(T2N-TN) = --------
                3              4-1

                1              4^2S2N-SN
    CN = S2N + ----(S2N-SN) = -----------
                15               4^2-1

                1              4^3C2N-CN
    RN = C2N + ----(C2N-CN) = -----------
                63              4^3-1

    参考 李信真, 车刚明, 欧阳洁, 等. 计算方法. 西北工业大学
       出版社, 2000, pp 162-164.
------------------------------------------------------
输入   :
    fun     被积分函数
    a, b    积分范围
    tol     控制误差
    Nn      最大循环步数
输出   :
    sol     解
    err     解出标志：false-未解出或达到步数上限；
                     true-全部解出
------------------------------------------------------
*/

package goNum

import (
	"math"
)

// IntegralRumberg Rumberg(龙贝格)求积分公式
func IntegralRumberg(fun func(float64) float64, a, b, tol float64, Nn int) (float64, bool) {
	/*
		Rumberg(龙贝格)求积分公式
		输入   :
		    fun     被积分函数
		    a, b    积分范围
		    tol     控制误差
		    Nn      最大循环步数
		输出   :
		    sol     解
		    err     解出标志：false-未解出或达到步数上限；
		                     true-全部解出
	*/

	T := make([]float64, 0) //梯形序列
	S := make([]float64, 0) //辛浦生序列
	C := make([]float64, 0) //柯特斯序列
	R := make([]float64, 0) //龙贝格序列
	//第一步
	temp0 := (b - a) * (fun(a) + fun(b)) / 2.0
	T = append(T, temp0) //T[0]=T1
	//第二步, k=1
	temp0 = 0.0
	for j := 1; j < PowIInt(2, 0)+1; j++ {
		temp0 += fun(a + (2.0*float64(j)-1.0)*(b-a)/2.0)
	}
	temp0 = T[0]/2.0 + temp0*(b-a)/2.0
	T = append(T, temp0) //T[1]=T2
	temp1 := T[1] + (T[1]-T[0])/3.0
	S = append(S, temp1) //S[0]=S1
	//第三步, k=2
	temp0 = 0.0
	for j := 1; j < PowIInt(2, 1)+1; j++ {
		temp0 += fun(a + (2.0*float64(j)-1.0)*(b-a)/(2.0*2.0))
	}
	temp0 = T[1]/2.0 + temp0*(b-a)/(2.0*2.0)
	T = append(T, temp0) //T[2]=T4
	temp1 = T[2] + (T[2]-T[1])/3.0
	S = append(S, temp1) //S[1]=S2
	temp2 := S[1] + (S[1]-S[0])/15.0
	C = append(C, temp2) //C[0]=C1
	//第四步, k=3
	temp0 = 0.0
	for j := 1; j < PowIInt(2, 2)+1; j++ {
		temp0 += fun(a + (2.0*float64(j)-1.0)*(b-a)/(2.0*4.0))
	}
	temp0 = T[2]/2.0 + temp0*(b-a)/(2.0*4.0)
	T = append(T, temp0) //T[3]=T8
	temp1 = T[3] + (T[3]-T[2])/3.0
	S = append(S, temp1) //S[2]=S4
	temp2 = S[2] + (S[2]-S[1])/15.0
	C = append(C, temp2) //C[1]=C2
	temp3 := C[1] + (C[1]-C[0])/63.0
	R = append(R, temp3) //R[0]=R1
	//进入Rumberg循环
	for i := 1; i < Nn; i++ {
		temp0 = 0.0
		for j := 1; j < PowIInt(2, i+2)+1; j++ {
			temp0 += fun(a + (2.0*float64(j)-1.0)*(b-a)/(2.0*PowIIntF(2, i+2)))
		}
		temp0 = T[i+2]/2.0 + temp0*(b-a)/(2.0*PowIIntF(2, i+2))
		T = append(T, temp0) //T[i+3]
		temp1 = T[i+3] + (T[i+3]-T[i+2])/3.0
		S = append(S, temp1) //S[i+2]
		temp2 = S[i+2] + (S[i+2]-S[i+1])/15.0
		C = append(C, temp2) //C[i+1]
		temp3 = C[i+1] + (C[i+1]-C[i])/63.0
		R = append(R, temp3) //R[i]

		if math.Abs(R[i]-R[i-1]) < tol {
			return R[i], true
		}
	}
	return 0.0, false
}
