begin % compare some numeric integration methods                             %

    long real procedure leftRect ( long real procedure f
                                 ; long real value     a, b
                                 ; integer   value     n
                                 ) ;
    begin
        long real h, sum, x;
        h   := (b - a) / n;
        sum := 0;
        x   := a;
        while x <= b - h do begin
            sum := sum + (h * f(x));
            x   := x + h
        end;
        sum
    end leftRect ;

    long real procedure rightRect ( long real procedure f
                                  ; long real value     a, b
                                  ; integer   value     n
                                  ) ;
    begin
        long real h, sum, x;
        h   := (b - a) / n;
        sum := 0;
        x   := a + h;
        while x <= b do begin
            sum := sum + (h * f(x));
            x   := x + h
        end;
        sum
    end rightRect ;

    long real procedure midRect ( long real procedure f
                                ; long real value     a, b
                                ; integer   value     n
                                ) ;
    begin
        long real h, sum, x;
        h   := (b - a) / n;
        sum := 0;
        x   := a;
        while x <= b - h do begin
            sum := sum + h * f(x + h / 2);
            x   := x + h
        end;
        sum
    end midRect ;

    long real procedure trapezium ( long real procedure f
                                  ; long real value     a, b
                                  ; integer   value     n
                                  ) ;
    begin
        long real h, sum, x;
        h   := (b - a) / n;
        sum := f(a) + f(b);
        x   := 1;
        while x <= n - 1 do begin
            sum := sum + 2 * f(a + x * h );
            x   := x + 1
        end;
        (b - a) / (2 * n) * sum
    end trapezium ;

    long real procedure simpson ( long real procedure f
                                ; long real value     a, b
                                ; integer   value     n
                                ) ;
    begin
        long real h, sum1, sum2, x;
        integer   limit;
        h     := (b - a) / n;
        sum1  := 0;
        sum2  := 0;
        limit := n - 1;
        for i := 0 until limit do sum1 := sum1 + f(a + h * i + h / 2);
        for i := 1 until limit do sum2 := sum2 + f(a + h * i);
        h / 6 * (f(a) + f(b) + 4 * sum1 + 2 * sum2)
    end simpson ;

    % tests the above procedures                                             %
    procedure testIntegrators1 ( string(3) value     legend
                               ; long real procedure f
                               ; long real value     lowerLimit
                               ; long real value     upperLimit
                               ; integer   value     iterations
                               ) ;
        write( r_format := "A", r_w := 20, r_d := 6, s_w := 0,
             , legend
             , leftRect(  f, lowerLimit, upperLimit, iterations )
             , rightRect( f, lowerLimit, upperLimit, iterations )
             , midRect(   f, lowerLimit, upperLimit, iterations )
             , trapezium( f, lowerLimit, upperLimit, iterations )
             , simpson(   f, lowerLimit, upperLimit, iterations )
             );
    procedure testIntegrators2 ( string(3) value     legend
                               ; long real procedure f
                               ; long real value     lowerLimit
                               ; long real value     upperLimit
                               ; integer   value     iterations
                               ) ;
        write( r_format := "A", r_w := 16, r_d := 2, s_w := 0,
             , legend
             , leftRect(  f, lowerLimit, upperLimit, iterations ), "    "
             , rightRect( f, lowerLimit, upperLimit, iterations ), "    "
             , midRect(   f, lowerLimit, upperLimit, iterations ), "    "
             , trapezium( f, lowerLimit, upperLimit, iterations ), "    "
             , simpson(   f, lowerLimit, upperLimit, iterations ), "    "
             );

    begin % task test cases                                                  %
        long real procedure xCubed   ( long real value x ) ; x * x * x;
        long real procedure oneOverX ( long real value x ) ; 1 / x;
        long real procedure xValue   ( long real value x ) ; x;
        write( "   "
             , "           left rect"
             , "          right rect"
             , "            mid rect"
             , "           trapezium"
             , "             simpson"
            );
        testIntegrators1( "x^3", xCubed,   0,    1,     100 );
        testIntegrators1( "1/x", oneOverX, 1,  100,    1000 );
        testIntegrators2( "x  ", xValue,   0, 5000, 5000000 );
        testIntegrators2( "x  ", xValue,   0, 6000, 6000000 )
    end
end.


MsgBox % Rect("fun", 0, 1, 10,-1) ; 0.45 left
MsgBox % Rect("fun", 0, 1, 10)    ; 0.50 mid
MsgBox % Rect("fun", 0, 1, 10, 1) ; 0.55 right
MsgBox % Trapez("fun", 0, 1, 10)  ; 0.50
MsgBox % Simpson("fun", 0, 1, 10) ; 0.50

Rect(f,a,b,n,side=0) { ; side: -1=left, 0=midpoint, 1=right
   h := (b - a) / n
   sum := 0, a += (side-1)*h/2
   Loop %n%
      sum += %f%(a + h*A_Index)
   Return h*sum
}

Trapez(f,a,b,n) {
   h := (b - a) / n
   sum := 0
   Loop % n-1
      sum += %f%(a + h*A_Index)
   Return h/2 * (%f%(a) + %f%(b) + 2*sum)
}

Simpson(f,a,b,n) {
   h := (b - a) / n
   sum1 := sum2 := 0, ah := a - h/2
   Loop %n%
      sum1 += %f%(ah + h*A_Index)
   Loop % n-1
      sum2 += %f%(a + h*A_Index)
   Return h/6 * (%f%(a) + %f%(b) + 4*sum1 + 2*sum2)
}

fun(x) { ; linear test function
   Return x
}


FUNCTION leftRect(a, b, n)
     h = (b - a) / n
     sum = 0
     FOR x = a TO b - h STEP h
        sum = sum + h * (f(x))
     NEXT x
     leftRect = sum
END FUNCTION

FUNCTION rightRect(a, b, n)
     h = (b - a) / n
     sum = 0
     FOR x = a + h TO b STEP h
        sum = sum + h * (f(x))
     NEXT x
     rightRect = sum
END FUNCTION

FUNCTION midRect(a, b, n)
     h = (b - a) / n
     sum = 0
     FOR x = a + h / 2 TO b - h / 2 STEP h
        sum = sum + h * (f(x))
     NEXT x
     midRect = sum
END FUNCTION

FUNCTION trap(a, b, n)
     h = (b - a) / n
     sum = f(a) + f(b)
     FOR i = 1 TO n-1
        sum = sum + 2 * f((a + i * h))
     NEXT i
     trap = h / 2 * sum
END FUNCTION

FUNCTION simpson(a, b, n)
     h = (b - a) / n
     sum1 = 0
     sum2 = 0

     FOR i = 0 TO n-1
        sum1 = sum1 + f(a + h * i + h / 2)
     NEXT i

     FOR i = 1 TO n - 1
        sum2 = sum2 + f(a + h * i)
     NEXT i

     simpson = h / 6 * (f(a) + f(b) + 4 * sum1 + 2 * sum2)
END FUNCTION


      *FLOAT64
      @% = 12 : REM Column width

      PRINT "Function     Range          L-Rect      R-Rect      M-Rect      Trapeze     Simpson"
      FOR func% = 1 TO 4
        READ x$, l, h, s%
        PRINT x$, ; l " - " ; h, FNlrect(x$, l, h, s%) FNrrect(x$, l, h, s%) ;
        PRINT FNmrect(x$, l, h, s%) FNtrapeze(x$, l, h, s%) FNsimpson(x$, l, h, s%)
      NEXT
      END

      DATA "x^3", 0,    1,     100
      DATA "1/x", 1,  100,    1000
      DATA "x",   0, 5000, 5000000
      DATA "x",   0, 6000, 6000000

      DEF FNlrect(x$, a, b, n%)
      LOCAL i%, d, s, x
      d = (b - a) / n%
      x = a
      FOR i% = 1 TO n%
        s += d * EVAL(x$)
        x += d
      NEXT
      = s

      DEF FNrrect(x$, a, b, n%)
      LOCAL i%, d, s, x
      d = (b - a) / n%
      x = a
      FOR i% = 1 TO n%
        x += d
        s += d * EVAL(x$)
      NEXT
      = s

      DEF FNmrect(x$, a, b, n%)
      LOCAL i%, d, s, x
      d = (b - a) / n%
      x = a
      FOR i% = 1 TO n%
        x += d/2
        s += d * EVAL(x$)
        x += d/2
      NEXT
      = s

      DEF FNtrapeze(x$, a, b, n%)
      LOCAL i%, d, f, s, x
      d = (b - a) / n%
      x = b : f = EVAL(x$)
      x = a : s = d * (f + EVAL(x$)) / 2
      FOR i% = 1 TO n%-1
        x += d
        s += d * EVAL(x$)
      NEXT
      = s

      DEF FNsimpson(x$, a, b, n%)
      LOCAL i%, d, f, s1, s2, x
      d = (b - a) / n%
      x = b : f = EVAL(x$)
      x = a + d/2 : s1 = EVAL(x$)
      FOR i% = 1 TO n%-1
        x += d/2
        s2 += EVAL(x$)
        x += d/2
        s1 += EVAL(x$)
      NEXT
      x = a
      = (d / 6) * (f + EVAL(x$) + 4 * s1 + 2 * s2)


#include <stdio.h>
#include <stdlib.h>
#include <math.h>

double int_leftrect(double from, double to, double n, double (*func)())
{
   double h = (to-from)/n;
   double sum = 0.0, x;
   for(x=from; x <= (to-h); x += h)
      sum += func(x);
   return h*sum;
}

double int_rightrect(double from, double to, double n, double (*func)())
{
   double h = (to-from)/n;
   double sum = 0.0, x;
   for(x=from; x <= (to-h); x += h)
     sum += func(x+h);
   return h*sum;
}

double int_midrect(double from, double to, double n, double (*func)())
{
   double h = (to-from)/n;
   double sum = 0.0, x;
   for(x=from; x <= (to-h); x += h)
     sum += func(x+h/2.0);
   return h*sum;
}

double int_trapezium(double from, double to, double n, double (*func)())
{
   double h = (to - from) / n;
   double sum = func(from) + func(to);
   int i;
   for(i = 1;i < n;i++)
       sum += 2.0*func(from + i * h);
   return  h * sum / 2.0;
}

double int_simpson(double from, double to, double n, double (*func)())
{
   double h = (to - from) / n;
   double sum1 = 0.0;
   double sum2 = 0.0;
   int i;

   double x;

   for(i = 0;i < n;i++)
      sum1 += func(from + h * i + h / 2.0);

   for(i = 1;i < n;i++)
      sum2 += func(from + h * i);

   return h / 6.0 * (func(from) + func(to) + 4.0 * sum1 + 2.0 * sum2);
}


using System;
using System.Collections.Generic;
using System.Linq;

public class Interval
{
    public Interval(double leftEndpoint, double size)
    {
        LeftEndpoint = leftEndpoint;
        RightEndpoint = leftEndpoint + size;
    }

    public double LeftEndpoint
    {
        get;
        set;
    }

    public double RightEndpoint
    {
        get;
        set;
    }

    public double Size
    {
        get
        {
            return RightEndpoint - LeftEndpoint;
        }
    }

    public double Center
    {
        get
        {
            return (LeftEndpoint + RightEndpoint) / 2;
        }
    }

    public IEnumerable<Interval> Subdivide(int subintervalCount)
    {
        double subintervalSize = Size / subintervalCount;
        return Enumerable.Range(0, subintervalCount).Select(index => new Interval(LeftEndpoint + index * subintervalSize, subintervalSize));
    }
}

public class DefiniteIntegral
{
    public DefiniteIntegral(Func<double, double> integrand, Interval domain)
    {
        Integrand = integrand;
        Domain = domain;
    }

    public Func<double, double> Integrand
    {
        get;
        set;
    }

    public Interval Domain
    {
        get;
        set;
    }

    public double SampleIntegrand(ApproximationMethod approximationMethod, Interval subdomain)
    {
        switch (approximationMethod)
        {
            case ApproximationMethod.RectangleLeft:
                return Integrand(subdomain.LeftEndpoint);
            case ApproximationMethod.RectangleMidpoint:
                return Integrand(subdomain.Center);
            case ApproximationMethod.RectangleRight:
                return Integrand(subdomain.RightEndpoint);
            case ApproximationMethod.Trapezium:
                return (Integrand(subdomain.LeftEndpoint) + Integrand(subdomain.RightEndpoint)) / 2;
            case ApproximationMethod.Simpson:
                return (Integrand(subdomain.LeftEndpoint) + 4 * Integrand(subdomain.Center) + Integrand(subdomain.RightEndpoint)) / 6;
            default:
                throw new NotImplementedException();
        }
    }

    public double Approximate(ApproximationMethod approximationMethod, int subdomainCount)
    {
        return Domain.Size * Domain.Subdivide(subdomainCount).Sum(subdomain => SampleIntegrand(approximationMethod, subdomain)) / subdomainCount;
    }

    public enum ApproximationMethod
    {
        RectangleLeft,
        RectangleMidpoint,
        RectangleRight,
        Trapezium,
        Simpson
    }
}

public class Program
{
    private static void TestApproximationMethods(DefiniteIntegral integral, int subdomainCount)
    {
        foreach (DefiniteIntegral.ApproximationMethod approximationMethod in Enum.GetValues(typeof(DefiniteIntegral.ApproximationMethod)))
        {
            Console.WriteLine(integral.Approximate(approximationMethod, subdomainCount));
        }
    }

    public static void Main()
    {
        TestApproximationMethods(new DefiniteIntegral(x => x * x * x, new Interval(0, 1)), 10000);
        TestApproximationMethods(new DefiniteIntegral(x => 1 / x, new Interval(1, 99)), 1000);
        TestApproximationMethods(new DefiniteIntegral(x => x, new Interval(0, 5000)), 500000);
        TestApproximationMethods(new DefiniteIntegral(x => x, new Interval(0, 6000)), 6000000);
    }
}


// the integration routine
template<typename Method, typename F, typename Float>
 double integrate(F f, Float a, Float b, int steps, Method m)
{
  double s = 0;
  double h = (b-a)/steps;
  for (int i = 0; i < steps; ++i)
    s += m(f, a + h*i, h);
  return h*s;
}

// methods
class rectangular
{
public:
  enum position_type { left, middle, right };
  rectangular(position_type pos): position(pos) {}
  template<typename F, typename Float>
   double operator()(F f, Float x, Float h) const
  {
    switch(position)
    {
    case left:
      return f(x);
    case middle:
      return f(x+h/2);
    case right:
      return f(x+h);
    }
  }
private:
  const position_type position;
};

class trapezium
{
public:
  template<typename F, typename Float>
   double operator()(F f, Float x, Float h) const
  {
    return (f(x) + f(x+h))/2;
  }
};

class simpson
{
public:
  template<typename F, typename Float>
   double operator()(F f, Float x, Float h) const
  {
    return (f(x) + 4*f(x+h/2) + f(x+h))/6;
  }
};

// sample usage
double f(double x) { return x*x; }

// inside a function somewhere:
double rl = integrate(f, 0.0, 1.0, 10, rectangular(rectangular::left));
double rm = integrate(f, 0.0, 1.0, 10, rectangular(rectangular::middle));
double rr = integrate(f, 0.0, 1.0, 10, rectangular(rectangular::right));
double t  = integrate(f, 0.0, 1.0, 10, trapezium());
double s  = integrate(f, 0.0, 1.0, 10, simpson());


proc f1(x:real):real {
  return x**3;
}

proc f2(x:real):real {
  return 1/x;
}

proc f3(x:real):real {
  return x;
}

proc leftRectangleIntegration(a: real, b: real, N: int, f): real{
  var h: real = (b - a)/N;
  var sum: real = 0.0;
  var x_n: real;
  for n in 0..N-1 {
    x_n = a + n * h;
    sum = sum + f(x_n);
  }
  return h * sum;
}

proc rightRectangleIntegration(a: real, b: real, N: int, f): real{
  var h: real = (b - a)/N;
  var sum: real = 0.0;
  var x_n: real;
  for n in 0..N-1 {
    x_n = a + (n + 1) * h;
    sum = sum + f(x_n);
  }
  return h * sum;
}

proc midpointRectangleIntegration(a: real, b: real, N: int, f): real{
  var h: real = (b - a)/N;
  var sum: real = 0.0;
  var x_n: real;
  for n in 0..N-1 {
    x_n = a + (n + 0.5) * h;
    sum = sum + f(x_n);
  }
  return h * sum;
}

proc trapezoidIntegration(a: real(64), b: real(64), N: int(64), f): real{
  var h: real(64) = (b - a)/N;
  var sum: real(64) = f(a) + f(b);
  var x_n: real(64);
  for n in 1..N-1 {
    x_n = a + n * h;
    sum = sum + 2.0 * f(x_n);
  }
  return (h/2.0) * sum;
}

proc simpsonsIntegration(a: real(64), b: real(64), N: int(64), f): real{
  var h: real(64) = (b - a)/N;
  var sum: real(64) = f(a) + f(b);
  var x_n: real(64);
  for n in 1..N-1 by 2 {
    x_n = a + n * h;
    sum = sum + 4.0 * f(x_n);
  }
  for n in 2..N-2 by 2 {
    x_n = a + n * h;
    sum = sum + 2.0 * f(x_n);
  }
  return (h/3.0) * sum;
}

var exact:real;
var calculated:real;

writeln("f(x) = x**3 with 100 steps from 0 to 1");
exact = 0.25;
calculated = leftRectangleIntegration(a = 0.0, b = 1.0, N = 100, f = f1);
writeln("leftRectangleIntegration: calculated = ", calculated, "; exact = ", exact, "; difference = ", abs(calculated - exact));
calculated = rightRectangleIntegration(a = 0.0, b = 1.0, N = 100, f = f1);
writeln("rightRectangleIntegration: calculated = ", calculated, "; exact = ", exact, "; difference = ", abs(calculated - exact));
calculated = midpointRectangleIntegration(a = 0.0, b = 1.0, N = 100, f = f1);
writeln("midpointRectangleIntegration: calculated = ", calculated, "; exact = ", exact, "; difference = ", abs(calculated - exact));
calculated = trapezoidIntegration(a = 0.0, b = 1.0, N = 100, f = f1);
writeln("trapezoidIntegration: calculated = ", calculated, "; exact = ", exact, "; difference = ", abs(calculated - exact));
calculated = simpsonsIntegration(a = 0.0, b = 1.0, N = 100, f = f1);
writeln("simpsonsIntegration: calculated = ", calculated, "; exact = ", exact, "; difference = ", abs(calculated - exact));
writeln();

writeln("f(x) = 1/x with 1000 steps from 1 to 100");
exact = 4.605170;
calculated = leftRectangleIntegration(a = 1.0, b = 100.0, N = 1000, f = f2);
writeln("leftRectangleIntegration: calculated = ", calculated, "; exact = ", exact, "; difference = ", abs(calculated - exact));
calculated = rightRectangleIntegration(a = 1.0, b = 100.0, N = 1000, f = f2);
writeln("rightRectangleIntegration: calculated = ", calculated, "; exact = ", exact, "; difference = ", abs(calculated - exact));
calculated = midpointRectangleIntegration(a = 1.0, b = 100.0, N = 1000, f = f2);
writeln("midpointRectangleIntegration: calculated = ", calculated, "; exact = ", exact, "; difference = ", abs(calculated - exact));
calculated = trapezoidIntegration(a = 1.0, b = 100.0, N = 1000, f = f2);
writeln("trapezoidIntegration: calculated = ", calculated, "; exact = ", exact, "; difference = ", abs(calculated - exact));
calculated = simpsonsIntegration(a = 1.0, b = 100.0, N = 1000, f = f2);
writeln("simpsonsIntegration: calculated = ", calculated, "; exact = ", exact, "; difference = ", abs(calculated - exact));
writeln();

writeln("f(x) = x with 5000000 steps from 0 to 5000");
exact = 12500000;
calculated = leftRectangleIntegration(a = 0.0, b = 5000.0, N = 5000000, f = f3);
writeln("leftRectangleIntegration: calculated = ", calculated, "; exact = ", exact, "; difference = ", abs(calculated - exact));
calculated = rightRectangleIntegration(a = 0.0, b = 5000.0, N = 5000000, f = f3);
writeln("rightRectangleIntegration: calculated = ", calculated, "; exact = ", exact, "; difference = ", abs(calculated - exact));
calculated = midpointRectangleIntegration(a = 0.0, b = 5000.0, N = 5000000, f = f3);
writeln("midpointRectangleIntegration: calculated = ", calculated, "; exact = ", exact, "; difference = ", abs(calculated - exact));
calculated = trapezoidIntegration(a = 0.0, b = 5000.0, N = 5000000, f = f3);
writeln("trapezoidIntegration: calculated = ", calculated, "; exact = ", exact, "; difference = ", abs(calculated - exact));
calculated = simpsonsIntegration(a = 0.0, b = 5000.0, N = 5000000, f = f3);
writeln("simpsonsIntegration: calculated = ", calculated, "; exact = ", exact, "; difference = ", abs(calculated - exact));
writeln();

writeln("f(x) = x with 6000000 steps from 0 to 6000");
exact = 18000000;
calculated = leftRectangleIntegration(a = 0.0, b = 6000.0, N = 6000000, f = f3);
writeln("leftRectangleIntegration: calculated = ", calculated, "; exact = ", exact, "; difference = ", abs(calculated - exact));
calculated = rightRectangleIntegration(a = 0.0, b = 6000.0, N = 6000000, f = f3);
writeln("rightRectangleIntegration: calculated = ", calculated, "; exact = ", exact, "; difference = ", abs(calculated - exact));
calculated = midpointRectangleIntegration(a = 0.0, b = 6000.0, N = 6000000, f = f3);
writeln("midpointRectangleIntegration: calculated = ", calculated, "; exact = ", exact, "; difference = ", abs(calculated - exact));
calculated = trapezoidIntegration(a = 0.0, b = 6000.0, N = 6000000, f = f3);
writeln("trapezoidIntegration: calculated = ", calculated, "; exact = ", exact, "; difference = ", abs(calculated - exact));
calculated = simpsonsIntegration(a = 0.0, b = 6000.0, N = 6000000, f = f3);
writeln("simpsonsIntegration: calculated = ", calculated, "; exact = ", exact, "; difference = ", abs(calculated - exact));
writeln();


rules =
  left_rect: (f, x, h) -> f(x)
  mid_rect: (f, x, h) -> f(x+h/2)
  right_rect: (f, x, h) -> f(x+h)
  trapezium: (f, x, h) -> (f(x) + f(x+h)) / 2
  simpson: (f, x, h) -> (f(x) + 4 * f(x + h/2) + f(x+h)) / 6

functions =
  cube: (x) -> x*x*x
  reciprocal: (x) -> 1/x
  identity: (x) -> x

sum = (list) -> list.reduce ((a, b) -> a+b), 0

integrate = (f, a, b, steps, meth) ->
   h = (b-a) / steps
   h * sum(meth(f, a+i*h, h) for i in [0...steps])

# Tests
tests = [
  [0, 1, 100, 'cube']
  [1, 100, 1000, 'reciprocal']
  [0, 5000, 5000000, 'identity']
  [0, 6000, 6000000, 'identity']
]

for test in tests
  [a, b, steps, func_name] = test
  func = functions[func_name]
  console.log "-- tests for #{func_name} with #{steps} steps from #{a} to #{b}"
  for rule_name, rule of rules
    result = integrate func, a, b, steps, rule
    console.log rule_name, result


(defun left-rectangle (f a b n &aux (d (/ (- b a) n)))
  (* d (loop for x from a below b by d summing (funcall f x))))

(defun right-rectangle (f a b n &aux (d (/ (- b a) n)))
  (* d (loop for x from b above a by d summing (funcall f x))))

(defun midpoint-rectangle (f a b n &aux (d (/ (- b a) n)))
  (* d (loop for x from (+ a (/ d 2)) below b by d summing (funcall f x))))

(defun trapezium (f a b n &aux (d (/ (- b a) n)))
  (* (/ d 2)
     (+ (funcall f a)
        (* 2 (loop for x from (+ a d) below b by d summing (funcall f x)))
        (funcall f b))))

(defun simpson (f a b n)
  (loop with h = (/ (- b a) n)
        with sum1 = (funcall f (+ a (/ h 2)))
        with sum2 = 0
        for i from 1 below n
        do (incf sum1 (funcall f (+ a (* h i) (/ h 2))))
        do (incf sum2 (funcall f (+ a (* h i))))
        finally (return (* (/ h 6)
                           (+ (funcall f a)
                              (funcall f b)
                              (* 4 sum1)
                              (* 2 sum2))))))


import std.stdio, std.typecons, std.typetuple;

template integrate(alias method) {
    double integrate(F, Float)(in F f, in Float a,
                               in Float b, in int steps) {
        double s = 0.0;
        immutable double h = (b - a) / steps;
        foreach (i; 0 .. steps)
            s += method(f, a + h * i, h);
        return h * s;
    }
}

double rectangularLeft(F, Float)(in F f, in Float x, in Float h)
pure nothrow {
    return f(x);
}

double rectangularMiddle(F, Float)(in F f, in Float x, in Float h)
pure nothrow {
    return f(x + h / 2);
}

double rectangularRight(F, Float)(in F f, in Float x, in Float h)
pure nothrow {
    return f(x + h);
}

double trapezium(F, Float)(in F f, in Float x, in Float h)
pure nothrow {
    return (f(x) + f(x + h)) / 2;
}

double simpson(F, Float)(in F f, in Float x, in Float h)
pure nothrow {
    return (f(x) + 4 * f(x + h / 2) + f(x + h)) / 6;
}

void main() {
    immutable args = [
        tuple((double x) => x ^^ 3, 0.0, 1.0, 10),
        tuple((double x) => 1 / x, 1.0, 100.0, 1000),
        tuple((double x) => x, 0.0, 5_000.0, 5_000_000),
        tuple((double x) => x, 0.0, 6_000.0, 6_000_000)];

    alias TypeTuple!(integrate!rectangularLeft,
                     integrate!rectangularMiddle,
                     integrate!rectangularRight,
                     integrate!trapezium,
                     integrate!simpson) ints;

    alias TypeTuple!("rectangular left:   ",
                     "rectangular middle: ",
                     "rectangular right:  ",
                     "trapezium:          ",
                     "simpson:            ") names;

    foreach (a; args) {
        foreach (i, n; names)
            writefln("%s %f", n, ints[i](a.tupleof));
        writeln();
    }
}


program Numerical_integration;

{$APPTYPE CONSOLE}

uses
  System.SysUtils;

type
  TFx = TFunc<Double, Double>;

  TMethod = TFunc<TFx, Double, Double, Double>;

function RectLeft(f: TFx; x, h: Double): Double;
begin
  RectLeft := f(x);
end;

function RectMid(f: TFx; x, h: Double): Double;
begin
  RectMid := f(x + h / 2);
end;

function RectRight(f: TFx; x, h: Double): Double;
begin
  Result := f(x + h);
end;

function Trapezium(f: TFx; x, h: Double): Double;
begin
  Result := (f(x) + f(x + h)) / 2.0;
end;

function Simpson(f: TFx; x, h: Double): Double;
begin
  Result := (f(x) + 4 * f(x + h / 2) + f(x + h)) / 6.0;
end;

function Integrate(Method: TMethod; f: TFx; a, b: Double; n: Integer): Double;
var
  h: Double;
  k: integer;
begin
  Result := 0;
  h := (b - a) / n;
  for k := 0 to n - 1 do
    Result := Result + Method(f, a + k * h, h);
  Result := Result * h;
end;

function f1(x: Double): Double;
begin
  Result := x * x * x;
end;

function f2(x: Double): Double;
begin
  Result := 1 / x;
end;

function f3(x: Double): Double;
begin
  Result := x;
end;

var
  fs: array[0..3] of TFx;
  mt: array[0..4] of TMethod;
  fsNames: array of string = ['x^3', '1/x', 'x', 'x'];
  mtNames: array of string = ['RectLeft', 'RectMid', 'RectRight', 'Trapezium', 'Simpson'];
  limits: array of array of Double = [[0, 1, 100], [1, 100, 1000], [0, 5000,
    5000000], [0, 6000, 6000000]];
  i, j, n: integer;
  a, b: double;

begin
  fs[0] := f1;
  fs[1] := f2;
  fs[2] := f3;
  fs[3] := f3;

  mt[0] := RectLeft;
  mt[1] := RectMid;
  mt[2] := RectRight;
  mt[3] := Trapezium;
  mt[4] := Simpson;

  for i := 0 to High(fs) do
  begin
    Writeln('Integrate ' + fsNames[i]);
    a := limits[i][0];
    b := limits[i][1];
    n := Trunc(limits[i][2]);

    for j := 0 to High(mt) do
      Writeln(Format('%.6f', [Integrate(mt[j], fs[i], a, b, n)]));
  end;
  readln;
end.


pragma.enable("accumulator")

def leftRect(f, x, h) {
  return f(x)
}

def midRect(f, x, h) {
  return f(x + h/2)
}

def rightRect(f, x, h) {
  return f(x + h)
}

def trapezium(f, x, h) {
  return (f(x) + f(x+h)) / 2
}

def simpson(f, x, h) {
  return (f(x) + 4 * f(x + h / 2) + f(x+h)) / 6
}

def integrate(f, a, b, steps, meth) {
   def h := (b-a) / steps
   return h * accum 0 for i in 0..!steps { _ + meth(f, a+i*h, h) }
}


defmodule Numerical do
  @funs  ~w(leftrect midrect rightrect trapezium simpson)a

  def  leftrect(f, left,_right), do: f.(left)
  def   midrect(f, left, right), do: f.((left+right)/2)
  def rightrect(f,_left, right), do: f.(right)
  def trapezium(f, left, right), do: (f.(left)+f.(right))/2
  def   simpson(f, left, right), do: (f.(left) + 4*f.((left+right)/2.0) + f.(right)) / 6.0

  def integrate(f, a, b, steps) when is_integer(steps) do
    delta = (b - a) / steps
    Enum.each(@funs, fn fun ->
      total = Enum.reduce(0..steps-1, 0, fn i, acc ->
        left = a + delta * i
        acc + apply(Numerical, fun, [f, left, left+delta])
      end)
      :io.format "~10s : ~.6f~n", [fun, total * delta]
    end)
  end
end

f1 = fn x -> x * x * x end
IO.puts "f(x) = x^3, where x is [0,1], with 100 approximations."
Numerical.integrate(f1, 0, 1, 100)

f2 = fn x -> 1 / x end
IO.puts "\nf(x) = 1/x, where x is [1,100], with 1,000 approximations. "
Numerical.integrate(f2, 1, 100, 1000)

f3 = fn x -> x end
IO.puts "\nf(x) = x, where x is [0,5000], with 5,000,000 approximations."
Numerical.integrate(f3, 0, 5000, 5_000_000)

f4 = fn x -> x end
IO.puts "\nf(x) = x, where x is [0,6000], with 6,000,000 approximations."
Numerical.integrate(f4, 0, 6000, 6_000_000)


function int_leftrect(sequence bounds, integer n, integer func_id)
    atom h, sum
    h = (bounds[2]-bounds[1])/n
    sum = 0
    for x = bounds[1] to bounds[2]-h by h do
        sum += call_func(func_id, {x})
    end for
    return h*sum
end function

function int_rightrect(sequence bounds, integer n, integer func_id)
    atom h, sum
    h = (bounds[2]-bounds[1])/n
    sum = 0
    for x = bounds[1] to bounds[2]-h by h do
        sum += call_func(func_id, {x+h})
    end for
    return h*sum
end function

function int_midrect(sequence bounds, integer n, integer func_id)
    atom h, sum
    h = (bounds[2]-bounds[1])/n
    sum = 0
    for x = bounds[1] to bounds[2]-h by h do
        sum += call_func(func_id, {x+h/2})
    end for
    return h*sum
end function

function int_trapezium(sequence bounds, integer n, integer func_id)
    atom h, sum
    h = (bounds[2]-bounds[1])/n
    sum = call_func(func_id, {bounds[1]}) + call_func(func_id, {bounds[2]})
    for x = bounds[1] to bounds[2]-h by h do
        sum += 2*call_func(func_id, {x})
    end for
    return h * sum / 2
end function

function int_simpson(sequence bounds, integer n, integer func_id)
    atom h, sum1, sum2
    h = (bounds[2]-bounds[1])/n
    sum1 = call_func(func_id, {bounds[1] + h/2})
    sum2 = 0
    for i = 1 to n-1 do
        sum1 += call_func(func_id, {bounds[1] + h * i + h / 2})
        sum2 += call_func(func_id, {bounds[1] + h * i})
    end for
    return h/6 * (call_func(func_id, {bounds[1]}) +
                  call_func(func_id, {bounds[2]}) + 4*sum1 + 2*sum2)
end function

function xp2d2(atom x)
    return x*x/2
end function

function logx(atom x)
    return log(x)
end function

function x(atom x)
    return x
end function

? int_leftrect({-1,1},1000,routine_id("xp2d2"))
? int_rightrect({-1,1},1000,routine_id("xp2d2"))
? int_midrect({-1,1},1000,routine_id("xp2d2"))
? int_simpson({-1,1},1000,routine_id("xp2d2"))
puts(1,'\n')
? int_leftrect({1,2},1000,routine_id("logx"))
? int_rightrect({1,2},1000,routine_id("logx"))
? int_midrect({1,2},1000,routine_id("logx"))
? int_simpson({1,2},1000,routine_id("logx"))
puts(1,'\n')
? int_leftrect({0,10},1000,routine_id("x"))
? int_rightrect({0,10},1000,routine_id("x"))
? int_midrect({0,10},1000,routine_id("x"))
? int_simpson({0,10},1000,routine_id("x"))


// integration methods
let left f dx x = f x * dx
let right f dx x = f (x + dx) * dx
let mid f dx x = f (x + dx / 2.0) * dx
let trapez f dx x = (f x + f (x + dx)) * dx / 2.0
let simpson f dx x = (f x + 4.0 * f (x + dx / 2.0) + f (x + dx)) * dx / 6.0

// common integration function
let integrate a b f n method =
    let dx = (b - a) / float n
    [0..n-1] |> Seq.map (fun i -> a + float i * dx) |> Seq.sumBy (method f dx)

// test cases
let methods = [ left; right; mid; trapez; simpson ]
let cases = [
    (fun x -> x * x * x), 0.0, 1.0,    100
    (fun x -> 1.0 / x),   1.0, 100.0,  1000
    (fun x -> x),         0.0, 5000.0, 5000000
    (fun x -> x),         0.0, 6000.0, 6000000
]

// execute and output
Seq.allPairs cases methods
|> Seq.map (fun ((f, a, b, n), method) -> integrate a b f n method)
|> Seq.iter (printfn "%f")


USE: math.functions
IN: scratchpad 0 1 [ 3 ^ ] integrate-simpson .
1/4
IN: scratchpad 1000 num-steps set-global
IN: scratchpad 1.0 100 [ -1 ^ ] integrate-simpson .
4.605173316272971
IN: scratchpad 5000000 num-steps set-global
IN: scratchpad 0 5000 [ ] integrate-simpson .
12500000
IN: scratchpad 6000000 num-steps set-global
IN: scratchpad 0 6000 [ ] integrate-simpson .
18000000


fvariable step

defer method ( fn F: x -- fn[x] )

: left                    execute ;
: right  step [email protected]       f+ execute ;
: mid    step [email protected] 2e f/ f+ execute ;
: trap
  dup fdup  left
      fswap right f+  2e f/ ;
: simpson
  dup fdup  left
  dup fover mid 4e f* f+
      fswap right f+  6e f/ ;

: set-step ( n F: a b -- n F: a )
  fover f- dup 0 d>f f/ step f! ;

: integrate ( xt n F: a b -- F: sigma )
  set-step
  0e
  0 do
    dup fover method f+
    fswap step [email protected] f+ fswap
  loop
  drop fnip
  step [email protected] f* ;
 \ testing similar to the D example
: test
  ' is method  ' 4 -1e 2e integrate f. ;

: fn1  fsincos f+ ;
: fn2  fdup f* 4e f* 1e f+ 2e fswap f/ ;

7 set-precision
test left    fn2  \ 2.456897
test right   fn2  \ 2.245132
test mid     fn2  \ 2.496091
test trap    fn2  \ 2.351014
test simpson fn2  \ 2.447732


elemental function elemf(x)
   real :: elemf, x
   elemf = f(x)
end function elemf


' version 17-09-2015
' compile with: fbc -s console

#Define screen_width 1024
#Define screen_height 256
ScreenRes screen_width, screen_height, 8
Width screen_width\8, screen_height\16

Function f1(x As Double) As Double
    Return x^3
End Function

Function f2(x As Double) As Double
    Return 1/x
End Function

Function f3(x As Double) As Double
    Return x
End Function

Function leftrect(a As Double, b As Double, n As Double, _
ByVal f As Function (ByVal As Double) As Double) As Double

    Dim As Double sum, x = a, h = (b - a) / n

    For i As UInteger = 1 To n
        sum = sum + h * f(x)
        x = x + h
    Next

    leftrect = sum
End Function

Function rightrect(a As Double, b As Double, n As Double, _
ByVal f As Function (ByVal As Double) As Double) As Double

    Dim As Double sum, x = a, h = (b - a) / n

    For i As UInteger = 1 To n
        x = x + h
        sum = sum + h * f(x)
    Next

    rightrect = sum
End Function

Function midrect(a As Double, b As Double, n As Double, _
ByVal f As Function (ByVal As Double) As Double) As Double

    Dim As Double sum, h = (b - a) / n, x = a + h / 2

    For i As UInteger = 1 To n
        sum = sum + h * f(x)
        x = x + h
    Next

    midrect = sum
End Function

Function trap(a As Double, b As Double, n As Double, _
ByVal f As Function (ByVal As Double) As Double) As Double

    Dim As Double x = a, h = (b - a) / n
    Dim As Double sum = h * (f(a) + f(b)) / 2

    For i As UInteger = 1 To n -1
        x = x + h
        sum = sum + h * f(x)
    Next

    trap = sum
End Function

Function simpson(a As Double, b As Double, n As Double, _
ByVal f As Function (ByVal As Double) As Double) As Double

    Dim As UInteger i
    Dim As Double sum1, sum2
    Dim As Double h = (b - a) / n

    For i = 0 To n -1
        sum1 = sum1 + f(a + h * i + h / 2)
    Next i

    For i = 1 To n -1
        sum2 = sum2 + f(a + h * i)
    Next i

    simpson = h / 6 * (f(a) + f(b) + 4 * sum1 + 2 * sum2)
End Function

' ------=< main >=------

Dim As Double y
Dim As String frmt = " ##.##########"

Print
Print "function     range       steps  leftrect      midrect       " + _
                              "rightrect     trap          simpson "

Print "f(x) = x^3   0 - 1         100";
Print Using frmt; leftrect(0, 1, 100, @f1); midrect(0, 1, 100, @f1); _
rightrect(0, 1, 100, @f1); trap(0, 1, 100, @f1); simpson(0, 1, 100, @f1)

Print "f(x) = 1/x   1 - 100      1000";
Print Using frmt; leftrect(1, 100, 1000, @f2); midrect(1, 100, 1000, @f2); _
                    rightrect(1, 100, 1000, @f2); trap(1, 100, 1000, @f2); _
                    simpson(1, 100, 1000, @f2)

frmt = " #########.###"
Print "f(x) = x     0 - 5000  5000000";
Print Using frmt; leftrect(0, 5000, 5000000, @f3); midrect(0, 5000, 5000000, @f3); _
                    rightrect(0, 5000, 5000000, @f3); trap(0, 5000, 5000000, @f3); _
                    simpson(0, 5000, 5000000, @f3)

Print "f(x) = x     0 - 6000  6000000";
Print Using frmt; leftrect(0, 6000, 6000000, @f3); midrect(0, 6000, 6000000, @f3); _
                    rightrect(0, 6000, 6000000, @f3); trap(0, 6000, 6000000, @f3); _
                    simpson(0, 6000, 6000000, @f3)

' empty keyboard buffer
While InKey <> "" : Wend
Print : Print "hit any key to end program"
Sleep
End


package main

import (
    "fmt"
    "math"
)

// specification for an integration
type spec struct {
    lower, upper float64               // bounds for integration
    n            int                   // number of parts
    exact        float64               // expected answer
    fs           string                // mathematical description of function
    f            func(float64) float64 // function to integrate
}

// test cases per task description
var data = []spec{
    spec{0, 1, 100, .25, "x^3", func(x float64) float64 { return x * x * x }},
    spec{1, 100, 1000, float64(math.Log(100)), "1/x",
        func(x float64) float64 { return 1 / x }},
    spec{0, 5000, 5e5, 12.5e6, "x", func(x float64) float64 { return x }},
    spec{0, 6000, 6e6, 18e6, "x", func(x float64) float64 { return x }},
}

// object for associating a printable function name with an integration method
type method struct {
    name      string
    integrate func(spec) float64
}

// integration methods implemented per task description
var methods = []method{
    method{"Rectangular (left)    ", rectLeft},
    method{"Rectangular (right)   ", rectRight},
    method{"Rectangular (midpoint)", rectMid},
    method{"Trapezium             ", trap},
    method{"Simpson's             ", simpson},
}

func rectLeft(t spec) float64 {
    var a adder
    r := t.upper - t.lower
    nf := float64(t.n)
    x0 := t.lower
    for i := 0; i < t.n; i++ {
        x1 := t.lower + float64(i+1)*r/nf
        // x1-x0 better than r/nf.
        // (with r/nf, the represenation error accumulates)
        a.add(t.f(x0) * (x1 - x0))
        x0 = x1
    }
    return a.total()
}

func rectRight(t spec) float64 {
    var a adder
    r := t.upper - t.lower
    nf := float64(t.n)
    x0 := t.lower
    for i := 0; i < t.n; i++ {
        x1 := t.lower + float64(i+1)*r/nf
        a.add(t.f(x1) * (x1 - x0))
        x0 = x1
    }
    return a.total()
}

func rectMid(t spec) float64 {
    var a adder
    r := t.upper - t.lower
    nf := float64(t.n)
    // there's a tiny gloss in the x1-x0 trick here.  the correct way
    // would be to compute x's at division boundaries, but we don't need
    // those x's for anything else.  (the function is evaluated on x's
    // at division midpoints rather than division boundaries.)  so, we
    // reuse the midpoint x's, knowing that they will average out just
    // as well.  we just need one extra point, so we use lower-.5.
    x0 := t.lower - .5*r/nf
    for i := 0; i < t.n; i++ {
        x1 := t.lower + (float64(i)+.5)*r/nf
        a.add(t.f(x1) * (x1 - x0))
        x0 = x1
    }
    return a.total()
}

func trap(t spec) float64 {
    var a adder
    r := t.upper - t.lower
    nf := float64(t.n)
    x0 := t.lower
    f0 := t.f(x0)
    for i := 0; i < t.n; i++ {
        x1 := t.lower + float64(i+1)*r/nf
        f1 := t.f(x1)
        a.add((f0 + f1) * .5 * (x1 - x0))
        x0, f0 = x1, f1
    }
    return a.total()
}

func simpson(t spec) float64 {
    var a adder
    r := t.upper - t.lower
    nf := float64(t.n)
    // similar to the rectangle midpoint logic explained above,
    // we play a little loose with the values used for dx and dx0.
    dx0 := r / nf
    a.add(t.f(t.lower) * dx0)
    a.add(t.f(t.lower+dx0*.5) * dx0 * 4)
    x0 := t.lower + dx0
    for i := 1; i < t.n; i++ {
        x1 := t.lower + float64(i+1)*r/nf
        xmid := (x0 + x1) * .5
        dx := x1 - x0
        a.add(t.f(x0) * dx * 2)
        a.add(t.f(xmid) * dx * 4)
        x0 = x1
    }
    a.add(t.f(t.upper) * dx0)
    return a.total() / 6
}

func sum(v []float64) float64 {
    var a adder
    for _, e := range v {
        a.add(e)
    }
    return a.total()
}

type adder struct {
    sum, e float64
}

func (a *adder) total() float64 {
    return a.sum + a.e
}

func (a *adder) add(x float64) {
    sum := a.sum + x
    e := sum - a.sum
    a.e += a.sum - (sum - e) + (x - e)
    a.sum = sum
}

func main() {
    for _, t := range data {
        fmt.Println("Test case: f(x) =", t.fs)
        fmt.Println("Integration from", t.lower, "to", t.upper,
            "in", t.n, "parts")
        fmt.Printf("Exact result            %.7e     Error\n", t.exact)
        for _, m := range methods {
            a := m.integrate(t)
            e := a - t.exact
            if e < 0 {
                e = -e
            }
            fmt.Printf("%s  %.7e  %.7e\n", m.name, a, e)
        }
        fmt.Println("")
    }
}


def assertBounds = { List bounds, int nRect ->
    assert (bounds.size() == 2) && (bounds[0] instanceof Double) && (bounds[1] instanceof Double) && (nRect > 0)
}

def integral = { List bounds, int nRectangles, Closure f, List pointGuide, Closure integralCalculator->
    double a = bounds[0], b = bounds[1], h = (b - a)/nRectangles
    def xPoints = pointGuide.collect { double it -> a + it*h }
    def fPoints = xPoints.collect { x -> f(x) }
    integralCalculator(h, fPoints)
}

def leftRectIntegral = { List bounds, int nRect, Closure f ->
    assertBounds(bounds, nRect)
    integral(bounds, nRect, f, (0..<nRect)) { h, fPoints -> h*fPoints.sum() }
}

def rightRectIntegral = { List bounds, int nRect, Closure f ->
    assertBounds(bounds, nRect)
    integral(bounds, nRect, f, (1..nRect)) { h, fPoints -> h*fPoints.sum() }
}

def midRectIntegral = { List bounds, int nRect, Closure f ->
    assertBounds(bounds, nRect)
    integral(bounds, nRect, f, ((0.5d)..nRect)) { h, fPoints -> h*fPoints.sum() }
}

def trapezoidIntegral = { List bounds, int nRect, Closure f ->
    assertBounds(bounds, nRect)
    integral(bounds, nRect, f, (0..nRect)) { h, fPoints ->
        def fLeft  = fPoints[0..<nRect]
        def fRight = fPoints[1..nRect]
        h/2*(fLeft + fRight).sum()
    }
}

def simpsonsIntegral = { List bounds, int nSimpRect, Closure f ->
    assertBounds(bounds, nSimpRect)
    integral(bounds, nSimpRect*2, f, (0..(nSimpRect*2))) { h, fPoints ->
        def fLeft  = fPoints[(0..<nSimpRect*2).step(2)]
        def fMid   = fPoints[(1..<nSimpRect*2).step(2)]
        def fRight = fPoints[(2..nSimpRect*2).step(2)]
        h/3*((fLeft + fRight).sum() + 4*(fMid.sum()))
    }
}


approx f xs ws = sum [w * f x | (x,w) <- zip xs ws]


integrate=: adverb define
  'a b steps'=. 3{.y,128
  size=. (b - a)%steps
  size * +/ u |: 2 ]\ a + size * i.>:steps
)

rectangle=: adverb def 'u -: +/ y'

trapezium=: adverb def '-: +/ u y'

simpson  =: adverb def '6 %~ +/ 1 1 4 * u y, -:+/y'


class NumericalIntegration
{

  interface FPFunction
  {
    double eval(double n);
  }

  public static double rectangularLeft(double a, double b, int n, FPFunction f)
  {
    return rectangular(a, b, n, f, 0);
  }

  public static double rectangularMidpoint(double a, double b, int n, FPFunction f)
  {
    return rectangular(a, b, n, f, 1);
  }

  public static double rectangularRight(double a, double b, int n, FPFunction f)
  {
    return rectangular(a, b, n, f, 2);
  }

  public static double trapezium(double a, double b, int n, FPFunction f)
  {
    double range = checkParamsGetRange(a, b, n);
    double nFloat = (double)n;
    double sum = 0.0;
    for (int i = 1; i < n; i++)
    {
      double x = a + range * (double)i / nFloat;
      sum += f.eval(x);
    }
    sum += (f.eval(a) + f.eval(b)) / 2.0;
    return sum * range / nFloat;
  }

  public static double simpsons(double a, double b, int n, FPFunction f)
  {
    double range = checkParamsGetRange(a, b, n);
    double nFloat = (double)n;
    double sum1 = f.eval(a + range / (nFloat * 2.0));
    double sum2 = 0.0;
    for (int i = 1; i < n; i++)
    {
      double x1 = a + range * ((double)i + 0.5) / nFloat;
      sum1 += f.eval(x1);
      double x2 = a + range * (double)i / nFloat;
      sum2 += f.eval(x2);
    }
    return (f.eval(a) + f.eval(b) + sum1 * 4.0 + sum2 * 2.0) * range / (nFloat * 6.0);
  }

  private static double rectangular(double a, double b, int n, FPFunction f, int mode)
  {
    double range = checkParamsGetRange(a, b, n);
    double modeOffset = (double)mode / 2.0;
    double nFloat = (double)n;
    double sum = 0.0;
    for (int i = 0; i < n; i++)
    {
      double x = a + range * ((double)i + modeOffset) / nFloat;
      sum += f.eval(x);
    }
    return sum * range / nFloat;
  }

  private static double checkParamsGetRange(double a, double b, int n)
  {
    if (n <= 0)
      throw new IllegalArgumentException("Invalid value of n");
    double range = b - a;
    if (range <= 0)
      throw new IllegalArgumentException("Invalid range");
    return range;
  }

  private static void testFunction(String fname, double a, double b, int n, FPFunction f)
  {
    System.out.println("Testing function \"" + fname + "\", a=" + a + ", b=" + b + ", n=" + n);
    System.out.println("rectangularLeft: " + rectangularLeft(a, b, n, f));
    System.out.println("rectangularMidpoint: " + rectangularMidpoint(a, b, n, f));
    System.out.println("rectangularRight: " + rectangularRight(a, b, n, f));
    System.out.println("trapezium: " + trapezium(a, b, n, f));
    System.out.println("simpsons: " + simpsons(a, b, n, f));
    System.out.println();
    return;
  }

  public static void main(String[] args)
  {
    testFunction("x^3", 0.0, 1.0, 100, new FPFunction() {
        public double eval(double n) {
          return n * n * n;
        }
      }
    );

    testFunction("1/x", 1.0, 100.0, 1000, new FPFunction() {
        public double eval(double n) {
          return 1.0 / n;
        }
      }
    );

    testFunction("x", 0.0, 5000.0, 5000000, new FPFunction() {
        public double eval(double n) {
          return n;
        }
      }
    );

    testFunction("x", 0.0, 6000.0, 6000000, new FPFunction() {
        public double eval(double n) {
          return n;
        }
      }
    );

    return;
  }
}


// version 1.1.2

typealias Func = (Double) -> Double

fun integrate(a: Double, b: Double, n: Int, f: Func) {
    val h = (b - a) / n
    val sum = DoubleArray(5)
    for (i in 0 until n) {
        val x = a + i * h
        sum[0] += f(x)
        sum[1] += f(x + h / 2.0)
        sum[2] += f(x + h)
        sum[3] += (f(x) + f(x + h)) / 2.0
        sum[4] += (f(x) + 4.0 * f(x + h / 2.0) + f(x + h)) / 6.0
    }
    val methods = listOf("LeftRect ", "MidRect  ", "RightRect", "Trapezium", "Simpson  ")
    for (i in 0..4) println("${methods[i]} = ${"%f".format(sum[i] * h)}")
    println()
}

fun main(args: Array<String>) {
    integrate(0.0, 1.0, 100) { it * it * it }
    integrate(1.0, 100.0, 1_000) { 1.0 / it }
    integrate(0.0, 5000.0, 5_000_000) { it }
    integrate(0.0, 6000.0, 6_000_000) { it }
}


1) FUNCTIONS

{def left_rect {lambda {:f :x :h} {:f :x}}}
-> left_rect

{def mid_rect {lambda {:f :x :h} {:f {+ :x {/ :h 2}}}}}
-> mid_rect

{def right_rect {lambda {:f :x :h} {:f {+ :x :h}}}}
-> right_rect

{def trapezium {lambda {:f :x :h} {/ {+ {:f :x} {:f {+ :x :h}}} 2}}}
-> trapezium

{def simpson
 {lambda {:f :x :h}
  {/ {+ {:f :x} {* 4 {:f {+ :x {/ :h 2}}}} {:f {+ :x :h}}} 6}}}
-> simpson

{def cube {lambda {:x} {* :x :x :x}}}
-> cube

{def reciprocal {lambda {:x} {/ 1 :x}}}
-> reciprocal

{def identity {lambda {:x} :x}}
-> identity

{def integrate
 {lambda {:f :a :b :steps :meth}
  {let { {:f :f} {:a :a} {:steps :steps} {:meth :meth}
         {:h {/ {- :b :a} :steps}}
       } {* :h {+ {S.map {{lambda {:meth :f :a :h :i}
                                  {:meth :f {+ :a {* :i :h}} :h}
                                 } :meth :f :a :h}
                         {S.serie 1 :steps}} }}}}}
-> integrate

{def methods left_rect mid_rect right_rect trapezium simpson}
-> methods

2) TESTS

We apply the following template

{b ∫*function* from *a* to *b* steps *steps*}
{table
 {tr {td exact value:} {td *value*}}  // the awaited value
 {S.map {lambda {:m}
          {tr {td :m}
              {td {integrate *function* *a* *b* *steps* :m}} }}
        {methods}} }

to the given *functions* from *a* to *b* with *steps*
and we get:

∫x3 from 0 to 100 steps 100         (computed in 13ms)
exact value: 	0.25                  // 1/4
left_rect 	0.25502500000000006
mid_rect 	0.26013825000000007
right_rect 	0.26532800000000006
trapezium 	0.2601765
simpson 	0.260151

∫1/x from 1 to 100 steps 1000       (computed in 94ms)
exact value: 	4.605170185988092     // log(100)
left_rect 	4.55698105751468
mid_rect 	4.511421425235764
right_rect 	4.467888185754358
trapezium 	4.512434621634517
simpson 	4.511759157368674

∫x from 0 to 5000 steps 5000000     (computed in ... 560000m)
exact value: 	12500000              // 5000*5000/2
left_rect 	12500002.5
mid_rect 	12500005
right_rect 	12500007.5
trapezium 	12500005
simpson 	12500005

∫x from 0 to 6000 steps 6000      (computed in 420ms) too impatient for 6000000, sorry
exact value: 	18000000            // 6000*6000/2
left_rect 	18003000
mid_rect 	18006000
right_rect 	18009000
trapezium 	18006000
simpson 	18006000


while 1
    read x$
    if x$ ="end" then print "**Over**": end

    read a, b, N, knownValue

    print " Function y ="; x$; " from "; a; " to "; b; " in "; N; " steps"
    print " Known exact value ="; knownValue

    areaLR = IntegralByLeftRectangle(   x$, a, b, N)
    areaRR = IntegralByRightRectangle(  x$, a, b, N)
    areaMR = IntegralByMiddleRectangle( x$, a, b, N)
    areaTr = IntegralByTrapezium(       x$, a, b, N)
    areaSi = IntegralBySimpsonRule(     x$, a, b, N)

    print "Left rectangle method   "; using( "##########.##########", areaLR); " diff "; knownValue-areaLR; tab(70); (knownValue-areaLR)/knownValue*100;" %"
    print "Right rectangle method  "; using( "##########.##########", areaRR); " diff "; knownValue-areaRR; tab(70); (knownValue-areaRR)/knownValue*100;" %"
    print "Middle rectangle method "; using( "##########.##########", areaMR); " diff "; knownValue-areaMR; tab(70); (knownValue-areaMR)/knownValue*100;" %"
    print "Trapezium  method       "; using( "##########.##########", areaTr); " diff "; knownValue-areaTr; tab(70); (knownValue-areaTr)/knownValue*100;" %"
    print "Simpson's Rule          "; using( "##########.##########", areaSi); " diff "; knownValue-areaSi; tab(70); (knownValue-areaSi)/knownValue*100;" %"

    print

wend

end

'------------------------------------------------------
    'we have N sizes, that gives us N+1 points
    'point 0 is a
    'point N is b
    'point i is xi =a +i *h
    'Often, precision is (sharper?) then single step area
    'So there should be EXACT number of steps, hence loop by integer i.

function IntegralByLeftRectangle( x$, a, b, N)
    h = ( b -a) /N
    s = 0
    for i = 0 to N -1
        x = a +i *h
        s = s + h *eval( x$)
    next
    IntegralByLeftRectangle = s
end function

function IntegralByRightRectangle( x$, a, b, N)
    h =( b -a) /N
    s = 0
    for i =1 to N
        x = a +i *h
        s = s + h *eval( x$)
    next
    IntegralByRightRectangle = s
end function

function IntegralByMiddleRectangle( x$, a, b, N)
    h =( b -a) /N
    s = 0
    for i =0 to N -1
        x = a +i *h +h /2
        s = s + h *eval( x$)
    next
    IntegralByMiddleRectangle = s
end function

function IntegralByTrapezium( x$, a, b, N)
'Formula is h*((f(a)+f(b))/2 + sum_{i=1}^{N-1} (f(x_i)))
    h  =( b -a) /N
    x  = a
    fa =eval( x$)
    x  =b
    fb =eval( x$)
    s = h *( fa +fb) /2
    for i =1 to N -1
        x = a +i *h
        s = s + h *eval( x$)
    next
    IntegralByTrapezium = s
end function

function IntegralBySimpsonRule( x$, a, b, N)
    'Simpson
    'N should be even.
    if N mod 2 then N =N +1
    'It really doesn't look right to double number of points from N to 2N -
    ' - this method is most accurate of all presented!
    'So we use NN as N/2, and N will be 2NN
    'Formula is h/6*( f(a)+f(b) + 4*(f(x_1)+f(x_3)+...+f(x_{2NN-1})+ 2*(f(x_2)+f(x_4)+...+f(x_{2NN-2})) )
    'Somehow I messed up h/6, h/3 and what is h, regarding "n=number of double intervals of size 2h"
    NN =N /2

    h  =( b -a) /N
    x  =a
    fa =eval (x$)
    x  =b
    fb =eval( x$)
    s = h /3 *( fa +fb)
    for i =1 to 2 *NN -1 step 2
        x = a +i *h
        s = s + h /3 *4 *eval( x$)  'odd points
    next
    for i =2 to 2 *NN -2 step 2
        x = a +i *h
        s = s + h /3 *2 *eval( x$)  'even points
    next

    IntegralBySimpsonRule = s
end function

'=======================================================
data "x^3",  0,    1,     100,          0.25
data "x^-1", 1,  100,    1000,          4.605170
data "x",    0, 5000,    1000,   12500000.0   '   should use 5 000 000 steps
data "x",    0, 6000,    1000,   18000000.0   '   should use 6 000 000 steps
data "end"

end


to i.left :fn :x :step
  output invoke :fn :x
end
to i.right :fn :x :step
  output invoke :fn :x + :step
end
to i.mid :fn :x :step
  output invoke :fn :x + :step/2
end
to i.trapezium :fn :x :step
  output ((i.left :fn :x :step) + (i.right :fn :x :step)) / 2
end
to i.simpsons :fn :x :step
  output ( (i.left :fn :x :step)
         + (i.mid :fn :x :step) * 4
         + (i.right :fn :x :step) ) / 6
end

to integrate :method :fn :steps :a :b
  localmake "step (:b - :a) / :steps
  localmake "sigma 0
  ; for [x :a :b-:step :step] [make "sigma :sigma + apply :method (list :fn :x :step)]
  repeat :steps [
    make "sigma :sigma + (invoke :method :fn :a :step)
    make "a :a + :step ]
  output :sigma * :step
end

to fn2 :x
  output 2 / (1 + 4 * :x * :x)
end
print integrate "i.left      "fn2 4 -1 2  ; 2.456897
print integrate "i.right     "fn2 4 -1 2  ; 2.245132
print integrate "i.mid       "fn2 4 -1 2  ; 2.496091
print integrate "i.trapezium "fn2 4 -1 2  ; 2.351014
print integrate "i.simpsons  "fn2 4 -1 2  ; 2.447732


function leftRect( f, a, b, n )
    local h = (b - a) / n
    local x = a
    local sum = 0

    for i = 1, 100 do
        sum = sum + a + f(x)
        x = x + h
    end

    return sum * h
end

function rightRect( f, a, b, n )
    local h = (b - a) / n
    local x = b
    local sum = 0

    for i = 1, 100 do
        sum = sum + a + f(x)
        x = x - h
    end

    return sum * h
end

function midRect( f, a, b, n )
    local h = (b - a) / n
    local x = a + h/2
    local sum = 0

    for i = 1, 100 do
        sum = sum + a + f(x)
        x = x + h
    end

    return sum * h
end

function trapezium( f, a, b, n )
    local h = (b - a) / n
    local x = a
    local sum = 0

    for i = 1, 100 do
        sum = sum + f(x)*2
        x = x + h
    end

    return (b - a) * sum / (2 * n)
end

function simpson( f, a, b, n )
    local h = (b - a) / n
    local sum1 = f(a + h/2)
    local sum2 = 0

    for i = 1, n-1 do
        sum1 = sum1 + f(a + h * i + h/2)
        sum2 = sum2 + f(a + h * i)
    end

    return (h/6) * (f(a) + f(b) + 4*sum1 + 2*sum2)
end

int_methods = { leftRect, rightRect, midRect, trapezium, simpson }
for i = 1, 5 do
    print( int_methods[i]( function(x) return x^3 end, 0, 1, 100 ) )
    print( int_methods[i]( function(x) return 1/x end, 1, 100, 1000 ) )
    print( int_methods[i]( function(x) return x end, 0, 5000, 5000000 ) )
    print( int_methods[i]( function(x) return x end, 0, 6000, 6000000 ) )
end


leftRect[f_, a_Real, b_Real, N_Integer] :=
 Module[{sum = 0, dx = (b - a)/N, x = a, n = N} ,
  For[n = N, n > 0, n--, x += dx; sum += f[x];];
  Return [ sum*dx ]]

rightRect[f_, a_Real, b_Real, N_Integer] :=
 Module[{sum = 0, dx = (b - a)/N, x = a + (b - a)/N, n = N} ,
  For[n = N, n > 0, n--, x += dx; sum += f[x];];
  Return [ sum*dx ]]

midRect[f_, a_Real, b_Real, N_Integer] :=
 Module[{sum = 0, dx = (b - a)/N, x = a + (b - a)/(2 N), n = N} ,
  For[n = N, n > 0, n--, x += dx; sum += f[x];];
  Return [ sum*dx ]]

trapezium[f_, a_Real, b_Real, N_Integer] :=
 Module[{sum = f[a], dx = (b - a)/N, x = a, n = N} ,
  For[n = 1, n < N, n++, x += dx; sum += 2 f[x];];
  sum += f[b];
  Return [ 0.5*sum*dx ]]

simpson[f_, a_Real, b_Real, N_Integer] :=
 Module[{sum1 = f[a + (b - a)/(2 N)], sum2 = 0, dx = (b - a)/N, x = a, n = N} ,
  For[n = 1, n < N, n++, sum1 += f[a + dx*n + dx/2];
   sum2 += f[a + dx*n];];
  Return [(dx/6)*(f[a] + f[b] + 4*sum1 + 2*sum2)]]


function integral = leftRectIntegration(f,a,b,n)

    format long;
    width = (b-a)/n; %calculate the width of each devision
    x = linspace(a,b,n); %define x-axis
    integral = width * sum( f(x(1:n-1)) );

end


right_rect(e, x, a, b, n) := block([h: (b - a) / n, s: 0],
   for i from 1 thru n do s: s + subst(x = a + i * h, e),
   s * h)$

left_rect(e, x, a, b, n) := block([h: (b - a) / n, s: 0],
   for i from 1 thru n do s: s + subst(x = a + (i - 1) * h, e),
   s * h)$

mid_rect(e, x, a, b, n) := block([h: (b - a) / n, s: 0],
   for i from 1 thru n do s: s + subst(x = a + (i - 1/2) * h, e),
   s * h)$

trapezium(e, x, a, b, n) := block([h: (b - a) / n, s: 0],
   for i from 1 thru n - 1 do s: s + subst(x = a + i * h, e),
   ((subst(x = a, e) + subst(x = b, e)) / 2 + s) * h)$

simpson(e, x, a, b, n) := block([h: (b - a) / n, s: 0],
   for i from 1 thru n do
      s: s + subst(x = a + i * h, e) + 2 * subst(x = a + (i - 1/2) * h, e),
   (subst(x = a, e) - subst(x = b, e) + 2 * s) * h / 6)$

/* some tests */

simpson(log(x), x, 1, 2, 20), bfloat;
2 * log(2) - 1 - %, bfloat;

trapezium(1/x, x, 1, 100, 10000) - log(100), bfloat;


type Function = proc(x: float): float
type Rule = proc(f: Function; x, h: float): float

proc leftRect(f: Function; x, h: float): float =
  f(x)

proc midRect(f: Function; x, h: float): float =
  f(x + h/2.0)

proc rightRect(f: Function; x, h: float): float =
  f(x + h)

proc trapezium(f: Function; x, h: float): float =
  (f(x) + f(x+h)) / 2.0

proc simpson(f: Function, x, h: float): float =
  (f(x) + 4.0*f(x+h/2.0) + f(x+h)) / 6.0

proc cube(x: float): float =
  x * x * x

proc reciprocal(x: float): float =
  1.0 / x

proc identity(x: float): float =
  x

proc integrate(f: Function; a, b: float; steps: int; meth: Rule): float =
  let h = (b-a) / float(steps)
  for i in 0 ..< steps:
    result += meth(f, a+float(i)*h, h)
  result = h * result

for fName, a, b, steps, fun in items(
   [("cube", 0, 1, 100, cube),
    ("reciprocal", 1, 100, 1000, reciprocal),
    ("identity", 0, 5000, 5_000_000, identity),
    ("identity", 0, 6000, 6_000_000, identity)]):

  for rName, rule in items({"leftRect": leftRect, "midRect": midRect,
      "rightRect": rightRect, "trapezium": trapezium, "simpson": simpson}):

    echo fName, " integrated using ", rName
    echo "  from ", a, " to ", b, " (", steps, " steps) = ",
      integrate(fun, float(a), float(b), steps, rule)


let integrate f a b steps meth =
  let h = (b -. a) /. float_of_int steps in
  let rec helper i s =
    if i >= steps then s
    else helper (succ i) (s +. meth f (a +. h *. float_of_int i) h)
  in
  h *. helper 0 0.


function RectLeft(function f(x: real): real; xl, xr: real): real;
 begin
  RectLeft := f(xl)
 end;

function RectMid(function f(x: real): real; xl, xr: real) : real;
 begin
  RectMid := f((xl+xr)/2)
 end;

function RectRight(function f(x: real): real; xl, xr: real): real;
 begin
  RectRight := f(xr)
 end;

function Trapezium(function f(x: real): real; xl, xr: real): real;
 begin
  Trapezium := (f(xl) + f(xr))/2
 end;

function Simpson(function f(x: real): real; xl, xr: real): real;
 begin
  Simpson := (f(xl) + 4*f((xl+xr)/2) + f(xr))/6
 end;

function integrate(function method(function f(x: real): real; xl, xr: real): real;
                   function f(x: real): real;
                   a, b: real;
                   n: integer);
 var
  integral, h: real;
  k: integer;
 begin
  integral := 0;
  h := (b-a)/n;
  for k := 0 to n-1 do
   begin
    integral := integral + method(f, a + k*h, a + (k+1)*h)
   end;
  integrate := integral
 end;


use feature 'say';

sub leftrect {
    my($func, $a, $b, $n) = @_;
    my $h = ($b - $a) / $n;
    my $sum = 0;
    for ($_ = $a; $_ < $b; $_ += $h) { $sum += $func->($_) }
    $h * $sum
}

sub rightrect {
    my($func, $a, $b, $n) = @_;
    my $h = ($b - $a) / $n;
    my $sum = 0;
    for ($_ = $a+$h; $_ < $b+$h; $_ += $h) { $sum += $func->($_) }
    $h * $sum
}

sub midrect {
    my($func, $a, $b, $n) = @_;
    my $h = ($b - $a) / $n;
    my $sum = 0;
    for ($_ = $a + $h/2; $_ < $b; $_ += $h) { $sum += $func->($_) }
    $h * $sum
}

sub trapez {
    my($func, $a, $b, $n) = @_;
    my $h = ($b - $a) / $n;
    my $sum = $func->($a) + $func->($b);
    for ($_ = $a+$h; $_ < $b; $_ += $h) { $sum += 2 * $func->($_) }
    $h/2 * $sum
}
sub simpsons {
    my($func, $a, $b, $n) = @_;
    my $h = ($b - $a) / $n;
    my $h2 = $h/2;
    my $sum1 = $func->($a + $h2);
    my $sum2 = 0;

    for ($_ = $a+$h; $_ < $b; $_ += $h) {
        $sum1 += $func->($_ + $h2);
        $sum2 += $func->($_);
    }
    $h/6 * ($func->($a) + $func->($b) + 4*$sum1 + 2*$sum2)
}

# round where needed, display in a reasonable format
sub sig {
    my($value) = @_;
    my $rounded;
    if ($value < 10) {
        $rounded = sprintf '%.6f', $value;
        $rounded =~ s/(\.\d*[1-9])0+$/$1/;
        $rounded =~ s/\.0+$//;
    } else {
        $rounded = sprintf "%.1f", $value;
        $rounded =~ s/\.0+$//;
    }
    return $rounded;
}

sub integrate {
    my($func, $a, $b, $n, $exact) = @_;

    my $f = sub { local $_ = shift; eval $func };

    my @res;
    push @res, "$func\n   in [$a..$b] / $n";
    push @res, '              exact result: ' . rnd($exact);
    push @res, '     rectangle method left: ' . rnd( leftrect($f, $a, $b, $n));
    push @res, '    rectangle method right: ' . rnd(rightrect($f, $a, $b, $n));
    push @res, '      rectangle method mid: ' . rnd(  midrect($f, $a, $b, $n));
    push @res, 'composite trapezoidal rule: ' . rnd(   trapez($f, $a, $b, $n));
    push @res, '   quadratic simpsons rule: ' . rnd( simpsons($f, $a, $b, $n));
    @res;
}
say for integrate('$_ ** 3', 0, 1, 100, 0.25); say '';
say for integrate('1 / $_', 1, 100, 1000, log(100)); say '';
say for integrate('$_', 0, 5_000, 5_000_000, 12_500_000); say '';
say for integrate('$_', 0, 6_000, 6_000_000, 18_000_000);


function rect_left(integer rid, atom x, atom /*h*/)
    return rid(x)
end function

function rect_mid(integer rid, atom x, atom h)
    return rid(x+h/2)
end function

function rect_right(integer rid, atom x, atom h)
    return rid(x+h)
end function

function trapezium(integer rid, atom x, atom h)
    return (rid(x)+rid(x+h))/2
end function

function simpson(integer rid, atom x, atom h)
    return (rid(x)+4*rid(x+h/2)+rid(x+h))/6
end function

function cubed(atom x)
    return power(x,3)
end function

function recip(atom x)
    return 1/x
end function

function ident(atom x)
    return x
end function

function integrate(integer m_id, integer f_id, atom a, atom b, integer steps)
    atom accum = 0,
         h = (b-a)/steps
    for i=0 to steps-1 do
        accum += m_id(f_id,a+h*i,h)
    end for
    return h*accum
end function

function smartp(atom N)
    if N=floor(N) then return sprintf("%d",N) end if
    string res = sprintf("%12f",round(N,1000000))
    if find('.',res) then
        res = trim_tail(res,"0")
        res = trim_tail(res,".")
    end if
    return res
end function

procedure test(sequence tests)
    string name
    atom a, b, steps, rid
    printf(1,"Function     Range     Iterations       L-Rect       M-Rect       R-Rect      Trapeze      Simpson\n")
    for i=1 to length(tests) do
        {name,a,b,steps,rid} = tests[i]
        printf(1,"  %-5s %6d - %-5d %10d  %12s %12s %12s %12s %12s\n",{name,a,b,steps,
                            smartp(integrate(rect_left, rid,a,b,steps)),
                            smartp(integrate(rect_mid,  rid,a,b,steps)),
                            smartp(integrate(rect_right,rid,a,b,steps)),
                            smartp(integrate(trapezium, rid,a,b,steps)),
                            smartp(integrate(simpson,   rid,a,b,steps))})
    end for
end procedure

constant tests = {{"x^3", 0,    1,     100, cubed},
                  {"1/x", 1,  100,    1000, recip},
                  {"x",   0, 5000, 5000000, ident},
                  {"x",   0, 6000, 6000000, ident}}

test(tests)


(scl 6)

(de leftRect (Fun X)
   (Fun X) )

(de rightRect (Fun X H)
   (Fun (+ X H)) )

(de midRect (Fun X H)
   (Fun (+ X (/ H 2))) )

(de trapezium (Fun X H)
   (/ (+ (Fun X) (Fun (+ X H))) 2) )

(de simpson (Fun X H)
   (*/
      (+
         (Fun X)
         (* 4 (Fun (+ X (/ H 2))))
         (Fun (+ X H)) )
      6 ) )

(de square (X)
   (*/ X X 1.0) )

(de integrate (Fun From To Steps Meth)
   (let (H (/ (- To From) Steps)  Sum 0)
      (for (X From  (>= (- To H) X)  (+ X H))
         (inc 'Sum (Meth Fun X H)) )
      (*/ H Sum 1.0) ) )

(prinl (round (integrate square 3.0 7.0 30 simpson)))


integrals: procedure options (main);   /* 1 September 2019 */

f: procedure (x, function) returns (float(18));
   declare x float(18), function fixed binary;
   select (function);
      when (1) return (x**3);
      when (2) return (1/x);
      when (3) return (x);
      when (4) return (x);
   end;
end f;

   declare (a, b) fixed decimal (10);
   declare (rect_area, trap_area, Simpson) float(18);
   declare (d, dx) float(18);
   declare (S1, S2) float(18);
   declare N fixed decimal (15), function fixed binary;
   declare k fixed decimal (7,2);

   put ('     Rectangle-left           Rectangle-mid            Rectangle-right' ||
        '        Trapezoid                 Simpson');
   do function = 1 to 4;
      select(function);
         when (1) do; N = 100;     a = 0; b = 1;    end;
         when (2) do; N = 1000;    a = 1; b = 100;  end;
         when (3) do; N = 5000000; a = 0; b = 5000; end;
         when (4) do; N = 6000000; a = 0; b = 6000; end;
      end;

      dx = (b-a)/float(N);

      /* Rectangle method, left-side */
      rect_area = 0;
      do d = 0 to N-1;
         rect_area = rect_area + dx*f(a + d*dx, function);
      end;
      put skip edit (rect_area) (E(25, 15));

      /* Rectangle method, mid-point */
      rect_area = 0;
      do d = 0 to N-1;
         rect_area = rect_area + dx*f(a + d*dx + dx/2, function);
      end;
      put edit (rect_area) (E(25, 15));

      /* Rectangle method, right-side */
      rect_area = 0;
      do d = 1 to N;
         rect_area = rect_area + dx*f(a + d*dx, function);
      end;
      put edit (rect_area) (E(25, 15));

      /* Trapezoid method */
      trap_area = 0;
      do d = 0 to N-1;
         trap_area = trap_area + dx*(f(a+d*dx, function) + f(a+(d+1)*dx, function))/2;
      end;
      put edit (trap_area) (X(1), E(25, 15));

      /* Simpson's Rule */
      S1 = f(a+dx/2, function);
      S2 = 0;
      do d = 1 to N-1;
         S1 = S1 + f(a+d*dx+dx/2, function);
         S2 = S2 + f(a+d*dx, function);
      end;
      Simpson = dx * (f(a, function) + f(b, function) + 4*S1 + 2*S2) / 6;
      put edit (Simpson) (X(1), E(25, 15));
   end;

end integrals;


Prototype.d TestFunction(Arg.d)

Procedure.d LeftIntegral(Start, Stop, Steps, *func.TestFunction)
  Protected.d n=(Stop-Start)/Steps, sum, x=Start
  While x <= Stop-n
    sum + n * *func(x)
    x + n
  Wend
  ProcedureReturn sum
EndProcedure

Procedure.d MidIntegral(Start, Stop, Steps, *func.TestFunction)
  Protected.d n=(Stop-Start)/Steps, sum, x=Start
  While x <= Stop-n
    sum + n * *func(x+n/2)
    x + n
  Wend
  ProcedureReturn sum
EndProcedure

Procedure.d RightIntegral(Start, Stop, Steps, *func.TestFunction)
  Protected.d n=(Stop-Start)/Steps, sum, x=Start
  While x < Stop
    x + n
    sum + n * *func(x)
  Wend
  ProcedureReturn sum
EndProcedure

Procedure.d Trapezium(Start, Stop, Steps, *func.TestFunction)
  Protected.d n=(Stop-Start)/Steps, sum, x=Start
  While x<=Stop
    sum + n * (*func(x) + *func(x+n))/2
    x+n
  Wend
  ProcedureReturn sum
EndProcedure

Procedure.d Simpson(Start, Stop, Steps, *func.TestFunction)
  Protected.d n=(Stop-Start)/Steps, sum1, sum2, x=Start
  Protected i
  For i=0 To steps-1
    sum1+ *func(Start+n*i+n/2)
  Next
  For i=1 To Steps-1
    sum2+ *func(Start+n*i)
  Next
  ProcedureReturn n * (*func(Start)+ *func(Stop)+4*sum1+2*sum2) / 6
EndProcedure

;- Set up functions to integrate
Procedure.d Test1(n.d)
  ProcedureReturn n*n*n
EndProcedure

Procedure.d Test2(n.d)
  ProcedureReturn 1/n
EndProcedure

; This function should be integrated as a integer function, but for
; comparably this will stay as a float.
Procedure.d Test3(n.d)
  ProcedureReturn n
EndProcedure

;- Test the code & present the results
CompilerIf #PB_Compiler_Debugger
  MessageRequester("Notice!","Running this program in Debug-mode will be slow")
CompilerEndIf

; = 0.25
Define Answer$
Answer$="Left     ="+StrD(LeftIntegral (0,1,100,@Test1()))+#CRLF$
Answer$+"Mid      ="+StrD(MidIntegral  (0,1,100,@Test1()))+#CRLF$
Answer$+"Right    ="+StrD(RightIntegral(0,1,100,@Test1()))+#CRLF$
Answer$+"Trapezium="+StrD(Trapezium    (0,1,100,@Test1()))+#CRLF$
Answer$+"Simpson  ="+StrD(Simpson      (0,1,100,@Test1()))
MessageRequester("Answer should be 1/4",Answer$)

; = Ln(100) e.g. ~4.60517019...
Answer$="Left     ="+StrD(LeftIntegral  (1,100,1000,@Test2()))+#CRLF$
Answer$+"Mid      ="+StrD(MidIntegral   (1,100,1000,@Test2()))+#CRLF$
Answer$+"Right    ="+StrD(RightIntegral (1,100,1000,@Test2()))+#CRLF$
Answer$+"Trapezium="+StrD(Trapezium     (1,100,1000,@Test2()))+#CRLF$
Answer$+"Simpson  ="+StrD(Simpson       (1,100,1000,@Test2()))
MessageRequester("Answer should be Ln(100), e.g. ~4.60517019",Answer$)

; 12,500,000
Answer$="Left     ="+StrD(LeftIntegral  (0,5000,5000000,@Test3()))+#CRLF$
Answer$+"Mid      ="+StrD(MidIntegral   (0,5000,5000000,@Test3()))+#CRLF$
Answer$+"Right    ="+StrD(RightIntegral (0,5000,5000000,@Test3()))+#CRLF$
Answer$+"Trapezium="+StrD(Trapezium     (0,5000,5000000,@Test3()))+#CRLF$
Answer$+"Simpson  ="+StrD(Simpson       (0,5000,5000000,@Test3()))
MessageRequester("Answer should be 12,500,000",Answer$)

; 18,000,000
Answer$="Left     ="+StrD(LeftIntegral  (0,6000,6000000,@Test3()))+#CRLF$
Answer$+"Mid      ="+StrD(MidIntegral   (0,6000,6000000,@Test3()))+#CRLF$
Answer$+"Right    ="+StrD(RightIntegral (0,6000,6000000,@Test3()))+#CRLF$
Answer$+"Trapezium="+StrD(Trapezium     (0,6000,6000000,@Test3()))+#CRLF$
Answer$+"Simpson  ="+StrD(Simpson       (0,6000,6000000,@Test3()))
MessageRequester("Answer should be 18,000,000",Answer$)


from fractions import Fraction

def left_rect(f,x,h):
  return f(x)

def mid_rect(f,x,h):
  return f(x + h/2)

def right_rect(f,x,h):
  return f(x+h)

def trapezium(f,x,h):
  return (f(x) + f(x+h))/2.0

def simpson(f,x,h):
  return (f(x) + 4*f(x + h/2) + f(x+h))/6.0

def cube(x):
  return x*x*x

def reciprocal(x):
  return 1/x

def identity(x):
  return x

def integrate( f, a, b, steps, meth):
   h = (b-a)/steps
   ival = h * sum(meth(f, a+i*h, h) for i in range(steps))
   return ival

# Tests
for a, b, steps, func in ((0., 1., 100, cube), (1., 100., 1000, reciprocal)):
    for rule in (left_rect, mid_rect, right_rect, trapezium, simpson):
        print('%s integrated using %s\n  from %r to %r (%i steps) = %r' %
              (func.__name__, rule.__name__, a, b, steps,
               integrate( func, a, b, steps, rule)))
    a, b = Fraction.from_float(a), Fraction.from_float(b)
    for rule in (left_rect, mid_rect, right_rect, trapezium, simpson):
        print('%s integrated using %s\n  from %r to %r (%i steps and fractions) = %r' %
              (func.__name__, rule.__name__, a, b, steps,
               float(integrate( func, a, b, steps, rule))))

# Extra tests (compute intensive)
for a, b, steps, func in ((0., 5000., 5000000, identity),
                          (0., 6000., 6000000, identity)):
    for rule in (left_rect, mid_rect, right_rect, trapezium, simpson):
        print('%s integrated using %s\n  from %r to %r (%i steps) = %r' %
              (func.__name__, rule.__name__, a, b, steps,
               integrate( func, a, b, steps, rule)))
    a, b = Fraction.from_float(a), Fraction.from_float(b)
    for rule in (left_rect, mid_rect, right_rect, trapezium, simpson):
        print('%s integrated using %s\n  from %r to %r (%i steps and fractions) = %r' %
              (func.__name__, rule.__name__, a, b, steps,
               float(integrate( func, a, b, steps, rule))))


#lang racket
(define (integrate f a b steps meth)
  (define h (/ (- b a) steps))
  (* h (for/sum ([i steps])
         (meth f (+ a (* h i)) h))))

(define (left-rect f x h) (f x))
(define (mid-rect f x h)  (f (+ x (/ h 2))))
(define (right-rect f x h)(f (+ x h)))
(define (trapezium f x h) (/ (+ (f x) (f (+ x h))) 2))
(define (simpson f x h)   (/ (+ (f x) (* 4 (f (+ x (/ h 2)))) (f (+ x h))) 6))

(define (test f a b s n)
  (displayln n)
  (for ([meth (list left-rect mid-rect right-rect trapezium simpson)]
        [name '(    left-rect mid-rect right-rect trapezium simpson)])
    (displayln (~a name ":\t" (integrate f a b s meth))))
  (newline))

(test (λ(x) (* x x x)) 0.    1.     100 "CUBED")
(test (λ(x) (/ x))     1.  100.    1000 "RECIPROCAL")
(test (λ(x) x)         0. 5000. 5000000 "IDENTITY")
(test (λ(x) x)         0. 6000. 6000000 "IDENTITY")


use MONKEY-SEE-NO-EVAL;

sub leftrect(&f, $a, $b, $n) {
    my $h = ($b - $a) / $n;
    my $end = $b-$h;
    my $sum = 0;
    loop (my $i = $a; $i <= $end; $i += $h) { $sum += f($i) }
    $h * $sum;
}

sub rightrect(&f, $a, $b, $n) {
    my $h = ($b - $a) / $n;
    my $sum = 0;
    loop (my $i = $a+$h; $i <= $b; $i += $h) { $sum += f($i) }
    $h * $sum;
}

sub midrect(&f, $a, $b, $n) {
    my $h = ($b - $a) / $n;
    my $sum = 0;
    my ($start, $end) = $a+$h/2, $b-$h/2;
    loop (my $i = $start; $i <= $end; $i += $h) { $sum += f($i) }
    $h * $sum;
}

sub trapez(&f, $a, $b, $n) {
    my $h = ($b - $a) / $n;
    my $partial-sum = 0;
    my ($start, $end) = $a+$h, $b-$h;
    loop (my $i = $start; $i <= $end; $i += $h) { $partial-sum += f($i) * 2 }
    $h / 2 * ( f($a) + f($b) + $partial-sum );
}

sub simpsons(&f, $a, $b, $n) {
    my $h = ($b - $a) / $n;
    my $h2 = $h/2;
    my ($start, $end) = $a+$h, $b-$h;
    my $sum1 = f($a + $h2);
    my $sum2 = 0;
    loop (my $i = $start; $i <= $end; $i += $h) {
        $sum1 += f($i + $h2);
        $sum2 += f($i);
    }
    ($h / 6) * (f($a) + f($b) + 4*$sum1 + 2*$sum2);
}

sub integrate($f, $a, $b, $n, $exact) {
    my $e = 0.000001;
    my $r0 = "$f\n   in [$a..$b] / $n\n"
        ~ '              exact result: '~ $exact.round($e);

    my ($r1,$r2,$r3,$r4,$r5);
    my &f;
    EVAL "&f = $f";
    my $p1 = Promise.start( { $r1 = '     rectangle method left: '~  leftrect(&f, $a, $b, $n).round($e) } );
    my $p2 = Promise.start( { $r2 = '    rectangle method right: '~ rightrect(&f, $a, $b, $n).round($e) } );
    my $p3 = Promise.start( { $r3 = '      rectangle method mid: '~   midrect(&f, $a, $b, $n).round($e) } );
    my $p4 = Promise.start( { $r4 = 'composite trapezoidal rule: '~    trapez(&f, $a, $b, $n).round($e) } );
    my $p5 = Promise.start( { $r5 = '   quadratic simpsons rule: '~  simpsons(&f, $a, $b, $n).round($e) } );

    await $p1, $p2, $p3, $p4, $p5;
    $r0, $r1, $r2, $r3, $r4, $r5;
}

.say for integrate '{ $_ ** 3 }', 0,     1,       100,       0.25; say '';
.say for integrate '1 / *',       1,   100,      1000,   log(100); say '';
.say for integrate '*.self',      0, 5_000, 5_000_000, 12_500_000; say '';
.say for integrate '*.self',      0, 6_000, 6_000_000, 18_000_000;


/*REXX pgm performs numerical integration using 5 different algorithms and show results.*/
numeric digits 20                                /*use twenty decimal digits precision. */

     do test=1  for 4;             say           /*perform the 4 different test suites. */
     if test==1  then do;    L= 0;     H=    1;     i=     100;     end
     if test==2  then do;    L= 1;     H=  100;     i=    1000;     end
     if test==3  then do;    L= 0;     H= 5000;     i= 5000000;     end
     if test==4  then do;    L= 0;     H= 6000;     i= 6000000;     end
     say center('test' test, 79, "═")            /*display a header for the test suite. */
     say '           left rectangular('L", "H', 'i")  ──► "         left_rect(L, H, i)
     say '       midpoint rectangular('L", "H', 'i")  ──► "     midpoint_rect(L, H, i)
     say '          right rectangular('L", "H', 'i")  ──► "        right_rect(L, H, i)
     say '                    Simpson('L", "H', 'i")  ──► "           Simpson(L, H, i)
     say '                  trapezium('L", "H', 'i")  ──► "         trapezium(L, H, i)
     end   /*test*/
exit                                             /*stick a fork in it,  we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
f:   parse arg y;  if test>2   then return y     /*choose the   "as─is"   function.     */
                   if test==1  then return y**3  /*   "    "     cube     function.     */
                                    return 1/y   /*   "    "  reciprocal     "          */
/*──────────────────────────────────────────────────────────────────────────────────────*/
left_rect:     procedure expose test; parse arg a,b,#;     $= 0;                h= (b-a)/#
                             do x=a      by h  for #;      $= $ + f(x)
                             end   /*x*/
               return $*h/1
/*──────────────────────────────────────────────────────────────────────────────────────*/
midpoint_rect: procedure expose test; parse arg a,b,#;     $= 0;                h= (b-a)/#
                             do x=a+h/2  by h  for #;      $= $ + f(x)
                             end   /*x*/
               return $*h/1
/*──────────────────────────────────────────────────────────────────────────────────────*/
right_rect:    procedure expose test; parse arg a,b,#;     $= 0;                h= (b-a)/#
                             do x=a+h    by h  for #;      $= $ + f(x)
                             end   /*x*/
               return $*h/1
/*──────────────────────────────────────────────────────────────────────────────────────*/
Simpson:       procedure expose test; parse arg a,b,#;                          h= (b-a)/#
               hh= h/2;                                    $= f(a + hh)
               @= 0;         do x=1  for #-1; hx=h*x + a;  @= @ + f(hx)
                                                           $= $ + f(hx + hh)
                             end   /*x*/

               return h * (f(a) + f(b) + 4*$ + 2*@)  /  6
/*──────────────────────────────────────────────────────────────────────────────────────*/
trapezium:     procedure expose test; parse arg a,b,#;     $= 0;                h= (b-a)/#
                             do x=a  by h  for #;          $= $ + (f(x) + f(x+h))
                             end   /*x*/
               return $*h/2


# Project : Numerical integration

decimals(8)
data = [["pow(x,3)",0,1,100], ["1/x",1, 100,1000], ["x",0,5000,5000000], ["x",0,6000,6000000]]
see "Function   Range   L-Rect   R-Rect   M-Rect   Trapeze   Simpson" + nl
for p = 1 to 4
     d1 = data[p][1]
     d2 = data[p][2]
     d3 = data[p][3]
     d4 = data[p][4]
     see "" + d1 + "   " + d2  + " - " + d3  + "   " + lrect(d1, d2, d3, d4) + "   " + rrect(d1, d2, d3, d4)
     see "  " + mrect(d1, d2, d3, d4) + "   " + trapeze(d1, d2, d3, d4) + "   " + simpson(d1, d2, d3, d4) + nl
next

func lrect(x2, a, b, n)
       s = 0
       d = (b - a) / n
       x = a
       for i = 1 to n
       eval("result = " + x2)
            s = s + d * result
            x = x + d
       next
       return s

func rrect(x2, a, b, n)
       s = 0
       d = (b - a) / n
       x = a
       for i = 1 to n
            x = x + d
            eval("result = " + x2)
            s = s + d *result
       next
       return s

func mrect(x2, a, b, n)
       s = 0
       d = (b - a) / n
       x = a
       for i = 1 to n
            x = x + d/2
            eval("result = " + x2)
            s = s + d * result
            x =  x +d/2
       next
       return s

func trapeze(x2, a, b, n)
       s = 0
       d = (b - a) / n
       x = b
       eval("result = " + x2)
       f = result
       x = a
       eval("result = " + x2)
       s = d * (f + result) / 2
       for i = 1 to n-1
            x = x + d
           eval("result = " + x2)
            s = s + d * result
       next
       return s

func simpson(x2, a, b, n)
        s1 = 0
        s = 0
        d = (b - a) / n
        x = b
        eval("result = " + x2)
        f = result
        x = a + d/2
       eval("result = " + x2)
        s1 = result
        for i = 1 to n-1
            x = x + d/2
            eval("result = " + x2)
            s = s + result
            x = x + d/2
            eval("result = " + x2)
            s1 = s1 + result
        next
        x = a
        eval("result = " + x2)
        return (d / 6) * (f + result + 4 * s1 + 2 * s)


def leftrect(f, left, right)
  f.call(left)
end

def midrect(f, left, right)
  f.call((left+right)/2.0)
end

def rightrect(f, left, right)
  f.call(right)
end

def trapezium(f, left, right)
  (f.call(left) + f.call(right)) / 2.0
end

def simpson(f, left, right)
  (f.call(left) + 4*f.call((left+right)/2.0) + f.call(right)) / 6.0
end

def integrate(f, a, b, steps, method)
  delta = 1.0 * (b - a) / steps
  total = 0.0
  steps.times do |i|
    left = a + i*delta
    right = left + delta
    total += delta * send(method, f, left, right)
  end
  total
end

def square(x)
  x**2
end

def def_int(f, a, b)
  l = case f.to_s
      when /sin>/
        lambda {|x| -Math.cos(x)}
      when /square>/
        lambda {|x| (x**3)/3.0}
      end
  l.call(b) - l.call(a)
end

a = 0
b = Math::PI
steps = 10

for func in [method(:square), Math.method(:sin)]
  puts "integral of #{func} from #{a} to #{b} in #{steps} steps"
  actual = def_int(func, a, b)
  for method in [:leftrect, :midrect, :rightrect, :trapezium, :simpson]
    int = integrate(func, a, b, steps, method)
    diff = (int - actual) * 100.0 / actual
    printf "   %-10s  %s\t(%.1f%%)\n", method, int, diff
  end
end


fn integral<F>(f: F, range: std::ops::Range<f64>, n_steps: u32) -> f64
    where F: Fn(f64) -> f64
{
    let step_size = (range.end - range.start)/n_steps as f64;

    let mut integral = (f(range.start) + f(range.end))/2.;
    let mut pos = range.start + step_size;
    while pos < range.end {
        integral += f(pos);
        pos += step_size;
    }
    integral * step_size
}

fn main() {
    println!("{}", integral(|x| x.powi(3), 0.0..1.0, 100));
    println!("{}", integral(|x| 1.0/x, 1.0..100.0, 1000));
    println!("{}", integral(|x| x, 0.0..5000.0, 5_000_000));
    println!("{}", integral(|x| x, 0.0..6000.0, 6_000_000));
}


object NumericalIntegration {
  def leftRect(f:Double=>Double, a:Double, b:Double)=f(a)
  def midRect(f:Double=>Double, a:Double, b:Double)=f((a+b)/2)
  def rightRect(f:Double=>Double, a:Double, b:Double)=f(b)
  def trapezoid(f:Double=>Double, a:Double, b:Double)=(f(a)+f(b))/2
  def simpson(f:Double=>Double, a:Double, b:Double)=(f(a)+4*f((a+b)/2)+f(b))/6;

  def fn1(x:Double)=x*x*x
  def fn2(x:Double)=1/x
  def fn3(x:Double)=x

  type Method = (Double=>Double, Double, Double) => Double
  def integrate(f:Double=>Double, a:Double, b:Double, steps:Double, m:Method)={
    val delta:Double=(b-a)/steps
    delta*(a until b by delta).foldLeft(0.0)((s,x) => s+m(f, x, x+delta))
  }

  def print(f:Double=>Double, a:Double, b:Double, steps:Double)={
    println("rectangular left   : %f".format(integrate(f, a, b, steps, leftRect)))
    println("rectangular middle : %f".format(integrate(f, a, b, steps, midRect)))
    println("rectangular right  : %f".format(integrate(f, a, b, steps, rightRect)))
    println("trapezoid          : %f".format(integrate(f, a, b, steps, trapezoid)))
    println("simpson            : %f".format(integrate(f, a, b, steps, simpson)))
  }

  def main(args: Array[String]): Unit = {
    print(fn1, 0, 1, 100)
    println("------")
    print(fn2, 1, 100, 1000)
    println("------")
    print(fn3, 0, 5000, 5000000)
    println("------")
    print(fn3, 0, 6000, 6000000)
  }
}


(define (integrate f a b steps meth)
  (define h (/ (- b a) steps))
  (* h
     (let loop ((i 0) (s 0))
       (if (>= i steps)
           s
           (loop (+ i 1) (+ s (meth f (+ a (* h i)) h)))))))

(define (left-rect f x h) (f x))
(define (mid-rect f x h) (f (+ x (/ h 2))))
(define (right-rect f x h) (f (+ x h)))
(define (trapezium f x h) (/ (+ (f x) (f (+ x h))) 2))
(define (simpson f x h) (/ (+ (f x) (* 4 (f (+ x (/ h 2)))) (f (+ x h))) 6))

(define (square x) (* x x))

(define rl (integrate square 0 1 10 left-rect))
(define rm (integrate square 0 1 10 mid-rect))
(define rr (integrate square 0 1 10 right-rect))
(define t (integrate square 0 1 10 trapezium))
(define s (integrate square 0 1 10 simpson))


import <Utilities/Conversion.sl>;
import <Utilities/Sequence.sl>;

integrateLeft(f, a, b, n) :=
    let
        h := (b - a) / n;
        vals[x] := f(x) foreach x within (0 ... (n-1)) * h + a;
    in
        h * sum(vals);

integrateRight(f, a, b, n) :=
    let
        h := (b - a) / n;
        vals[x] := f(x+h) foreach x within (0 ... (n-1)) * h + a;
    in
        h * sum(vals);

integrateMidpoint(f, a, b, n) :=
    let
        h := (b - a) / n;
        vals[x] := f(x+h/2.0) foreach x within (0 ... (n-1)) * h + a;
    in
        h * sum(vals);

integrateTrapezium(f, a, b, n) :=
    let
        h := (b - a) / n;
        vals[i] := 2.0 * f(a + i * h) foreach i within 1 ... n-1;
    in
        h * (sum(vals) + f(a) + f(b)) / 2.0;

integrateSimpsons(f, a, b, n) :=
    let
        h := (b - a) / n;
        vals1[i] := f(a + h * i + h / 2.0) foreach i within 0 ... n-1;
        vals2[i] :=  f(a + h * i) foreach i within 1 ... n-1;
    in
        h / 6.0 * (f(a) + f(b) + 4.0 * sum(vals1) + 2.0 * sum(vals2));

xCubed(x) := x^3;
xInverse(x) := 1/x;
identity(x) := x;

tests[method] :=
    [method(xCubed, 0.0, 1.0, 100),
     method(xInverse, 1.0, 100.0, 1000),
     method(identity, 0.0, 5000.0, 5000000),
     method(identity, 0.0, 6000.0, 6000000)]
     foreach method within [integrateLeft, integrateRight, integrateMidpoint, integrateTrapezium, integrateSimpsons];

//String manipulation for ouput display.
main :=
    let
        heading := [["Func", "Range\t", "L-Rect\t", "R-Rect\t", "M-Rect\t", "Trapezium", "Simpson"]];
        ranges := [["0 - 1\t", "1 - 100\t", "0 - 5000", "0 - 6000"]];
        funcs := [["x^3", "1/x", "x", "x"]];
    in
        delimit(delimit(heading ++ transpose(funcs ++ ranges ++ trimEndZeroes(floatToString(tests, 8))), '\t'), '\n');

trimEndZeroes(x(1)) := x when size(x) = 0 else x when x[size(x)] /= '0' else trimEndZeroes(x[1...size(x)-1]);


func sum(f, start, from, to) {
    var s = 0;
    RangeNum(start, to, from-start).each { |i|
        s += f(i);
    }
    return s
}

func leftrect(f, a, b, n) {
    var h = ((b - a) / n);
    h * sum(f, a, a+h, b-h);
}

func rightrect(f, a, b, n) {
    var h = ((b - a) / n);
    h * sum(f, a+h, a + 2*h, b);
}

func midrect(f, a, b, n) {
    var h = ((b - a) / n);
    h * sum(f, a + h/2, a + h + h/2, b - h/2)
}

func trapez(f, a, b, n) {
    var h = ((b - a) / n);
    h/2 * (f(a) + f(b) + sum({ f(_)*2 }, a+h, a + 2*h, b-h));
}

func simpsons(f, a, b, n) {
    var h = ((b - a) / n);
    var h2 = h/2;

    var sum1 = f(a + h2);
    var sum2 = 0;

    sum({|i| sum1 += f(i + h2); sum2 += f(i); 0 }, a+h, a+h+h, b-h);
    h/6 * (f(a) + f(b) + 4*sum1 + 2*sum2);
}

func tryem(label, f, a, b, n, exact) {
    say "\n#{label}\n   in [#{a}..#{b}] / #{n}";

    say('              exact result: ', exact);
    say('     rectangle method left: ', leftrect(f, a, b, n));
    say('    rectangle method right: ', rightrect(f, a, b, n));
    say('      rectangle method mid: ', midrect(f, a, b, n));
    say('composite trapezoidal rule: ', trapez(f, a, b, n));
    say('   quadratic simpsons rule: ', simpsons(f, a, b, n));
}

tryem('x^3', { _ ** 3 }, 0, 1, 100, 0.25);
tryem('1/x', { 1 / _ }, 1, 100, 1000, log(100));
tryem('x', { _ }, 0, 5_000, 5_000_000, 12_500_000);
tryem('x', { _ }, 0, 6_000, 6_000_000, 18_000_000);


fun integrate (f, a, b, steps, meth) = let
  val h = (b - a) / real steps
  fun helper (i, s) =
    if i >= steps then s
    else helper (i+1, s + meth (f, a + h * real i, h))
in
  h * helper (0, 0.0)
end

fun leftRect  (f, x, _) = f x
fun midRect   (f, x, h) = f (x + h / 2.0)
fun rightRect (f, x, h) = f (x + h)
fun trapezium (f, x, h) = (f x + f (x + h)) / 2.0
fun simpson   (f, x, h) = (f x + 4.0 * f (x + h / 2.0) + f (x + h)) / 6.0

fun square x = x * x

val rl = integrate (square, 0.0, 1.0, 10, left_rect )
val rm = integrate (square, 0.0, 1.0, 10, mid_rect  )
val rr = integrate (square, 0.0, 1.0, 10, right_rect)
val t  = integrate (square, 0.0, 1.0, 10, trapezium )
val s  = integrate (square, 0.0, 1.0, 10, simpson   )


mata
function integrate(f,a,b,n,u,v) {
	s = 0
	h = (b-a)/n
	m = length(u)
	for (i=0; i<n; i++) {
		x = a+i*h
		for (j=1; j<=m; j++) s = s+v[j]*(*f)(x+h*u[j])
	}
	return(s*h)
}

function log_(x) {
	return(log(x))
}

function id(x) {
	return(x)
}

function cube(x) {
	return(x*x*x)
}

function inv(x) {
	return(1/x)
}

function test(f,a,b,n) {
	return(integrate(f,a,b,n,(0,1),(1,0)),
	       integrate(f,a,b,n,(0,1),(0,1)),
	       integrate(f,a,b,n,(0.5),(1)),
	       integrate(f,a,b,n,(0,1),(0.5,0.5)),
	       integrate(f,a,b,n,(0,1/2,1),(1/6,4/6,1/6)))
}

test(&cube(),0,1,100)
test(&inv(),1,100,1000)
test(&id(),0,5000,5000000)
test(&id(),0,6000,6000000)
end


public enum IntegrationType : CaseIterable {
  case rectangularLeft
  case rectangularRight
  case rectangularMidpoint
  case trapezium
  case simpson
}

public func integrate(
  from: Double,
  to: Double,
  n: Int,
  using: IntegrationType = .simpson,
  f: (Double) -> Double
) -> Double {
  let integrationFunc: (Double, Double, Int, (Double) -> Double) -> Double

  switch using {
  case .rectangularLeft:
    integrationFunc = integrateRectL
  case .rectangularRight:
    integrationFunc = integrateRectR
  case .rectangularMidpoint:
    integrationFunc = integrateRectMid
  case .trapezium:
    integrationFunc = integrateTrapezium
  case .simpson:
    integrationFunc = integrateSimpson
  }

  return integrationFunc(from, to, n, f)
}

private func integrateRectL(from: Double, to: Double, n: Int, f: (Double) -> Double) -> Double {
  let h = (to - from) / Double(n)
  var x = from
  var sum = 0.0

  while x <= to - h {
    sum += f(x)
    x += h
  }

  return h * sum
}

private func integrateRectR(from: Double, to: Double, n: Int, f: (Double) -> Double) -> Double {
  let h = (to - from) / Double(n)
  var x = from
  var sum = 0.0

  while x <= to - h {
    sum += f(x + h)
    x += h
  }

  return h * sum
}

private func integrateRectMid(from: Double, to: Double, n: Int, f: (Double) -> Double) -> Double {
  let h = (to - from) / Double(n)
  var x = from
  var sum = 0.0

  while x <= to - h {
    sum += f(x + h / 2.0)
    x += h
  }

  return h * sum
}

private func integrateTrapezium(from: Double, to: Double, n: Int, f: (Double) -> Double) -> Double {
  let h = (to - from) / Double(n)
  var sum = f(from) + f(to)

  for i in 1..<n {
    sum += 2 * f(from + Double(i) * h)
  }

  return h * sum / 2
}

private func integrateSimpson(from: Double, to: Double, n: Int, f: (Double) -> Double) -> Double {
  let h = (to - from) / Double(n)
  var sum1 = 0.0
  var sum2 = 0.0

  for i in 0..<n {
    sum1 += f(from + h * Double(i) + h / 2.0)
  }

  for i in 1..<n {
    sum2 += f(from + h * Double(i))
  }

  return h / 6.0 * (f(from) + f(to) + 4.0 * sum1 + 2.0 * sum2)
}

let types = IntegrationType.allCases

print("f(x) = x^3:", types.map({ integrate(from: 0, to: 1, n: 100, using: $0, f: { pow($0, 3) }) }))
print("f(x) = 1 / x:", types.map({ integrate(from: 1, to: 100, n: 1000, using: $0, f: { 1 / $0 }) }))
print("f(x) = x, 0 -> 5_000:", types.map({ integrate(from: 0, to: 5_000, n: 5_000_000, using: $0, f: { $0 }) }))
print("f(x) = x, 0 -> 6_000:", types.map({ integrate(from: 0, to: 6_000, n: 6_000_000, using: $0, f: { $0 }) }))


package require Tcl 8.5

proc leftrect {f left right} {
    $f $left
}
proc midrect {f left right} {
    set mid [expr {($left + $right) / 2.0}]
    $f $mid
}
proc rightrect {f left right} {
    $f $right
}
proc trapezium {f left right} {
    expr {([$f $left] + [$f $right]) / 2.0}
}
proc simpson {f left right} {
    set mid [expr {($left + $right) / 2.0}]
    expr {([$f $left] + 4*[$f $mid] + [$f $right]) / 6.0}
}

proc integrate {f a b steps method} {
    set delta [expr {1.0 * ($b - $a) / $steps}]
    set total 0.0
    for {set i 0} {$i < $steps} {incr i} {
        set left [expr {$a + $i * $delta}]
        set right [expr {$left + $delta}]
        set total [expr {$total + $delta * [$method $f $left $right]}]
    }
    return $total
}

interp alias {} sin {} ::tcl::mathfunc::sin
proc square x {expr {$x*$x}}
proc def_int {f a b} {
    switch -- $f {
        sin    {set lambda {x {expr {-cos($x)}}}}
        square {set lambda {x {expr {$x**3/3.0}}}}
    }
    return [expr {[apply $lambda $b] - [apply $lambda $a]}]
}

set a 0
set b [expr {4*atan(1)}]
set steps 10

foreach func {square sin} {
    puts "integral of ${func}(x) from $a to $b in $steps steps"
    set actual [def_int $func $a $b]
    foreach method {leftrect midrect rightrect trapezium simpson} {
        set int [integrate $func $a $b $steps $method]
        set diff [expr {($int - $actual) * 100.0 / $actual}]
        puts [format "   %-10s  %s\t(%.1f%%)" $method $int $diff]
    }
}


#import std
#import nat
#import flo

(integral_by "m") ("f","a","b","n") =

iprod ^(* ! div\float"n" minus/"b" "a",~&) ("m" "f")*ytp (ari successor "n")/"a" "b"


Option Explicit
Option Base 1

Function Quad(ByVal f As String, ByVal a As Double, _
        ByVal b As Double, ByVal n As Long, _
        ByVal u As Variant, ByVal v As Variant) As Double
    Dim m As Long, h As Double, x As Double, s As Double, i As Long, j As Long
    m = UBound(u)
    h = (b - a) / n
    s = 0#
    For i = 1 To n
        x = a + (i - 1) * h
        For j = 1 To m
            s = s + v(j) * Application.Run(f, x + h * u(j))
        Next
    Next
    Quad = s * h
End Function

Function f1fun(x As Double) As Double
    f1fun = x ^ 3
End Function

Function f2fun(x As Double) As Double
    f2fun = 1 / x
End Function

Function f3fun(x As Double) As Double
    f3fun = x
End Function

Sub Test()
    Dim fun, f, coef, c
    Dim i As Long, j As Long, s As Double

    fun = Array(Array("f1fun", 0, 1, 100, 1 / 4), _
        Array("f2fun", 1, 100, 1000, Log(100)), _
        Array("f3fun", 0, 5000, 50000, 5000 ^ 2 / 2), _
        Array("f3fun", 0, 6000, 60000, 6000 ^ 2 / 2))

    coef = Array(Array("Left rect.  ", Array(0, 1), Array(1, 0)), _
        Array("Right rect. ", Array(0, 1), Array(0, 1)), _
        Array("Midpoint    ", Array(0.5), Array(1)), _
        Array("Trapez.     ", Array(0, 1), Array(0.5, 0.5)), _
        Array("Simpson     ", Array(0, 0.5, 1), Array(1 / 6, 4 / 6, 1 / 6)))

    For i = 1 To UBound(fun)
        f = fun(i)
        Debug.Print f(1)
        For j = 1 To UBound(coef)
            c = coef(j)
            s = Quad(f(1), f(2), f(3), f(4), c(2), c(3))
            Debug.Print "  " + c(1) + ": ", s, (s - f(5)) / f(5)
        Next j
    Next i
End Sub


import "/fmt" for Fmt

var integrate = Fn.new { |a, b, n, f|
    var h = (b - a) / n
    var sum = List.filled(5, 0)
    for (i in 0...n) {
        var x = a + i * h
        sum[0] = sum[0] + f.call(x)
        sum[1] = sum[1] + f.call(x + h/2)
        sum[2] = sum[2] + f.call(x + h)
        sum[3] = sum[3] + (f.call(x) + f.call(x+h))/2
        sum[4] = sum[4] + (f.call(x) + 4 * f.call(x + h/2) + f.call(x + h))/6
    }
    var methods = ["LeftRect ", "MidRect  ", "RightRect", "Trapezium", "Simpson  "]
    for (i in 0..4) Fmt.print("$s = $h", methods[i], sum[i] * h)
    System.print()
}

integrate.call(0, 1, 100)        { |v| v * v * v }
integrate.call(1, 100, 1000)     { |v| 1 / v }
integrate.call(0, 5000, 5000000) { |v| v }
integrate.call(0, 6000, 6000000) { |v| v }


include c:\cxpl\codes;          \intrinsic 'code' declarations

func real Func(FN, X);          \Return F(X) for function number FN
int  FN;  real X;
[case FN of
  1:  return X*X*X;
  2:  return 1.0/X;
  3:  return X
other return 0.0;
];

func Integrate(A, B, FN, N);    \Display area under curve for function FN
real A, B;  int FN, N;          \limits A, B, and number of slices N
real DX, X, Area;               \delta X
int  I;
[DX:= (B-A)/float(N);
X:= A;  Area:= 0.0;             \rectangular left
for I:= 1 to N do
    [Area:= Area + Func(FN,X)*DX;  X:= X+DX];
RlOut(0, Area);
X:= A;  Area:= 0.0;             \rectangular right
for I:= 1 to N do
    [X:= X+DX;  Area:= Area + Func(FN,X)*DX];
RlOut(0, Area);
X:= A+DX/2.0;  Area:= 0.0;      \rectangular mid point
for I:= 1 to N do
    [Area:= Area + Func(FN,X)*DX;  X:= X+DX];
RlOut(0, Area);
X:= A;  Area:= 0.0;             \trapezium
for I:= 1 to N do
    [Area:= Area + (Func(FN,X)+Func(FN,X+DX))/2.0*DX;  X:= X+DX];
RlOut(0, Area);
X:= A;  Area:= 0.0;             \Simpson's rule
for I:= 1 to N do
    [Area:= Area +
        DX/6.0*(Func(FN,X) + 4.0*Func(FN,(X+X+DX)/2.0) + Func(FN,X+DX));
    X:= X+DX];
RlOut(0, Area);
CrLf(0);
];

[Format(9,6);
Integrate(0.0, 1.0, 1, 100);
Integrate(1.0, 100.0, 2, 1000);
Integrate(0.0, 5000.0, 3, 5_000_000);
Integrate(0.0, 6000.0, 3, 6_000_000);
]


// Rosetta Code problem: https://rosettacode.org/wiki/Numerical_integration
// by Jjuanhdez, 06/2022

print "function     range       steps  leftrect      midrect       rightrect     trap          simpson "
frmt$ = "%1.10f"
print "f(x) = x^3   0 - 1         100  ";
Integrate(0.0, 1.0, 1, 100)
print "f(x) = 1/x   1 - 100      1000  ";
Integrate(1.0, 100.0, 2, 1000)
frmt$ = "%8.3f"
print "f(x) = x     0 - 5000  5000000  ";
Integrate(0.0, 5000.0, 3, 5000000)
print "f(x) = x     0 - 6000  6000000  ";
Integrate(0.0, 6000.0, 3, 6000000)
end

sub Func(FN, X)         //Return F(X) for function number FN
    switch FN
    case 1
        return X ^ 3
    case 2
        return 1.0 / X
    case 3
        return X
    default
        return 0.0
    end switch
end sub

sub Integrate(A, B, FN, N)    //Display area under curve for function FN
    // A, B, FN    limits A, B, and number of slices N

    DX = (B-A)/N
    X = A
    Area = 0.0             //rectangular left
    for i = 1 to N
        Area = Area + Func(FN,X)*DX
        X = X + DX
    next i
    print str$(Area, frmt$);
    X = A
    Area = 0.0             //rectangular right
    for i = 1 to N
        X = X + DX
        Area = Area + Func(FN,X)*DX
    next i
    print "  ";
    print str$(Area, frmt$);
    X = A + DX / 2.0
    Area = 0.0             //rectangular mid point
    for i = 1 to N
        Area = Area + Func(FN,X)*DX
        X = X + DX
    next i
    print "  ";
    print str$(Area, frmt$);
    X = A
    Area = 0.0             //trapezium
    for i = 1 to N
        Area = Area + (Func(FN,X)+Func(FN,X + DX))/2.0*DX
        X = X + DX
    next i
    print "  ";
    print str$(Area, frmt$);
    X = A
    Area = 0.0             //Simpson's rule
    for i = 1 to N
        Area = Area + DX/6.0*(Func(FN,X) + 4.0*Func(FN,(X+X + DX)/2.0) + Func(FN,X + DX))
        X = X + DX
    next i
    print "  ";
    print str$(Area, frmt$)
end sub


fcn integrate(F,f,a,b,steps){
   h:=(b - a) / steps;
   h*(0).reduce(steps,'wrap(s,i){ F(f, h*i + a, h) + s },0.0);
}

fcn rectangularLeft(f,x)    { f(x) }
fcn rectangularMiddle(f,x,h){ f(x+h/2) }
fcn rectangularRight(f,x,h) { f(x+h) }
fcn trapezium(f,x,h)        { (f(x) + f(x+h))/2 }
fcn simpson(f,x,h)	    { (f(x) + 4.0*f(x+h/2) + f(x+h))/6 }

args:=T( T(fcn(x){ x.pow(3) }, 0.0, 1.0,   10),
         T(fcn(x){ 1.0 / x },  1.0, 100.0, 1000),
         T(fcn(x){ x },        0.0, 5000.0, 0d5_000_000),
         T(fcn(x){ x },        0.0, 6000.0, 0d6_000_000) );
fs:=T(rectangularLeft,rectangularMiddle,rectangularRight,
      trapezium,simpson);
names:=fs.pump(List,"name",'+(":"),"%-18s".fmt);

foreach a in (args){
   names.zipWith('wrap(nm,f){
      "%s %f".fmt(nm,integrate(f,a.xplode())).println() }, fs);
   println();
}


F f([Int]? &a)
   I a != N
      a.append(1)

f(N)
[Int] arr
f(&arr)
print(arr)