package integral

import std.math.*
import std.util.*
foreign func malloc(size: UIntNative) : CPointer<Unit>

public func fun(x: Float64): Float64 {
  var y: Float64
  y = sqrt(4.0 - x * x)
  return y
}

public func Trape(fun: (Float64) -> Float64, down: Float64, up: Float64, n: Int32): Float64 {
  var h: Float64
  var s: Float64
  h = (up - down) / Float64(n)
  s = 0.5 * ( fun(down) + fun(down + h) ) * h 
  for (i in 1..n) {
    s = s + 0.5 * ( fun(down + Float64(i) * h) + fun(down + Float64(i + 1) * h) ) *h
  }

  return s
}

public class Trapzd {
  var a: Float64
  var b: Float64
  var s: Float64
  var n: Int32
  var f: (Float64) -> Float64
  init (aa: Float64, bb: Float64, fun: (Float64) -> Float64) {
    a = aa
	b = bb
	s = 0.0
	n = 0
	f = fun
  }
  func next(): Float64 {
    var x: Float64
	var tnm: Float64
	var sum: Float64
	var del: Float64
	var it: Int32
	n = n + 1
	if (n == 1) {
	  s = 0.5 * (b - a) * ( f(a) + f(b) )
	  return s
	} else {
	  it = 1
	  for (j in 1..n-1) {
        it = it * 2
	  }
	  tnm = Float64(it)
	  del = (b - a) / tnm
	  x = a + 0.5 * del
	  sum = 0.0
	  for (j in 0..it) {
	    sum = sum + f(x)
	    x = x + del
	  }
	  s = 0.5 * (s + (b - a) * sum / tnm )
	  return s
    }
  }
}

public func qtrap(fun: (Float64) -> Float64, a: Float64, b: Float64, eps: Float64): Float64 {
  let JMAX: Int32 = 20
  var s: Float64 = 0.0
  var old: Float64 = 0.0
  var t = Trapzd(a, b, fun)
  for (j in 0..JMAX) {
    s = t.next()
	if (j > 5) {
	  if (abs(s - old) < eps * abs(old) || (s == 0.0 && old == 0.0)) {
	    return s
	  }
	}
    old = s
  }
  throw IllegalArgumentException("Too many steps in routine qtrap")
}

public func qsimp(fun: (Float64) -> Float64, a: Float64, b: Float64, eps: Float64): Float64 {
  let JMAX: Int32 = 20
  var s: Float64
  var st: Float64
  var ost: Float64 = 0.0
  var os: Float64 = 0.0
  var t = Trapzd(a, b, fun)
  for (j in 0..JMAX) {
    st = t.next()
	s = ( 4.0 * st - ost ) / 3.0
	if (j > 5) {
	  if (abs(s - os) < eps * abs(os) || (s == 0.0 && os == 0.0)) {
	    return s
	  }
	}
	os = s
	ost = st
  }
  throw IllegalArgumentException("Too many steps in routine qsimp")
}

func qgaus(fun: (Float64) -> Float64, a: Float64, b: Float64): Float64 {
  let x = Array<Float64>([0.1488743389816312, 0.4333953941292472,
						  0.6794095682990244, 0.8650633666889845, 0.9739065285171717])
  let w = Array<Float64>([0.2955242247147529, 0.2692667193099963,
					      0.2190863625159821, 0.1494513491505806, 0.0666713443086881])
  var xm: Float64 = 0.5 * (b + a)
  var xr: Float64 = 0.5 * (b - a)
  var s: Float64 = 0.0
  for (j in 0..5) {
    var dx = xr * x[j]
	var x_r = xm + dx
	var x_l = xm - dx
	s = s + w[j] * (fun(x_r) + fun(x_l))
  }
  return s * xr
}

public func testIntegral()  {
  print("被积函数为: y = sqrt(4 - x ^ 2)\n\n")


  print("区间为[-1, 1]\n")//3.826445909962073
  var down: Float64 = -1.0
  var up: Float64 = 1.0
  var n: Int32 = 10

  var sum1 = Trape(fun, down, up, 513)
  var s = Trapzd(down, up, fun)
  var sum2: Float64
  for (i in 1..n) {
    sum2 = s.next()
  }
  var sum3 = qtrap(fun, down, up, 1e-6)
  var sum4 = qsimp(fun, down, up, 1e-6)
  var sum5 = qgaus(fun, down, up)
  print("梯形公式积分值为: ${ sum1 }\n")
  print("拓展梯形公式积分值为: ${ sum2 }\n")
  print("拓展梯形公式积分值(eps=1e-6)为: ${ sum3 }\n")
  print("辛普森公式积分值(eps=1e-6)为: ${ sum4 }\n")
  print("高斯公式积分值为: ${ sum5 }\n\n")

  print("区间为[-2, 2]\n")//6.283185307179593
  down = -2.0
  up = 2.0
  n = 10

  sum1 = Trape(fun, down, up, 513)
  s = Trapzd(down, up, fun)
  sum2 = 0.0
  for (i in 1..n) {
    sum2 = s.next()
  }
  sum3 = qtrap(fun, down, up, 1e-6)
  sum4 = qsimp(fun, down, up, 1e-6)
  sum5 = qgaus(fun, down, up)
  print("梯形公式积分值为: ${ sum1 }\n")
  print("拓展梯形公式积分值为: ${ sum2 }\n")
  print("拓展梯形公式积分值(eps=1e-6)为: ${ sum3 }\n")
  print("辛普森公式积分值(eps=1e-6)为: ${ sum4 }\n")
  print("高斯公式积分值为: ${ sum5 }\n")
}