Numerical integration: Difference between revisions

From Rosetta Code
Content added Content deleted
m (Simplified a few lines in BASIC and Java)
(added D code)
Line 322: Line 322:
double s = integrate(f, 0.0, 1.0, 10, simpson());
double s = integrate(f, 0.0, 1.0, 10, simpson());


=={{header|D}}==
The function f(x) is Func1/Func2 in this program.
<pre>module integrate ;
import std.stdio ;
import std.math ;

alias real function(real) realFn ;

class Sigma{
int n ;
real a, b , h ;
realFn fn ;
string desc ;
enum Method {LEFT = 0, RGHT, MIDD, TRAP, SIMP} ;
static string[5] methodName =
["LeftRect ", "RightRect", "MidRect ", "Trapezium", "Simpson "] ;
static Sigma opCall() {
Sigma s = new Sigma() ;
return s ;
}
static Sigma opCall(realFn f, int n, real a, real b) {
Sigma s = new Sigma(f, n, a, b) ;
return s ;
}
static real opCall(realFn f, int n, real a, real b, Method m) {
return Sigma(f,n,a,b).getSum(m) ;
}
private this() {} ;
this(realFn f, int n, real a, real b) {
setFunction(f) ;
setStep(n) ;
setRange(a,b) ;
}
Sigma opCall(Method m) {
return doSum(m) ;
}
Sigma setFunction(realFn f) {
this.fn = f ;
return this ;
}
Sigma setRange(real a, real b) {
this.a = a ; this.b = b ;
setInterval() ;
return this ;
}
Sigma setStep(int n) {
this.n = n ;
setInterval() ;
return this ;
}
Sigma setDesc(string d) {
this.desc = d ;
return this ;
}
private void setInterval() {
this.h = (b - a) / n ;
}
private real partSum(int i, Method m) {
real x = a + h * i ;
switch(m) {
case Method.LEFT:
return fn(x) ;
case Method.RGHT:
return fn(x + h) ;
case Method.MIDD:
return fn(x + h/2) ;
case Method.TRAP:
return (fn(x) + fn(x + h))/2 ;
default:
}
//case SIMPSON:
return (fn(x) + 4 * fn(x + h/2) + fn(x + h))/6 ;
}
real getSum(Method m) {
real sum = 0 ;
for(int i = 0; i < n ; i++)
sum += partSum(i, m) ;
return sum * h ;
}
Sigma doSum(Method m) {
writefln("%10s = %9.6f", methodName[m], getSum(m)) ;
return this ;
}
Sigma showSetting() {
writefln("\n%s\nA = %9.6f, B = %9.6f, N = %s, h = %s", desc, a, b, n, h) ;
return this ;
}
Sigma doLeft() { return doSum(Method.LEFT) ; }
Sigma doRight() { return doSum(Method.RGHT) ; }
Sigma doMid() { return doSum(Method.MIDD) ; }
Sigma doTrap() { return doSum(Method.TRAP) ; }
Sigma doSimp() { return doSum(Method.SIMP) ; }
Sigma doAll() {
showSetting() ;
doLeft() ; doRight() ; doMid() ; doTrap() ; doSimp() ;
return this ;
}
}
real Func1(real x) {
return cos(x) + sin(x) ;
}
real Func2(real x) {
return 2.0L/(1 + 4*x*x) ;
}
void main() {
// use as a re-usable and manageable object
Sigma s = Sigma(&Func1, 10, -PI/2, PI/2).showSetting()
.doLeft().doRight().doMid().doTrap()(Sigma.Method.SIMP) ;
s.setFunction(&Func2).setStep(4).setRange(-1.0L,2.0L) ;
s.setDesc("Function(x) = 2 / (1 + 4x^2)").doAll() ;
// use as a single function call
writefln("\nLeftRect Integral of FUNC2 =") ;
writefln("%12.9f (%3dstep)\n%12.9f (%3dstep)\n%12.9f (%3dstep).",
Sigma(&Func2, 8, -1.0L, 2.0L, Sigma.Method.LEFT), 8,
Sigma(&Func2, 64, -1.0L, 2.0L, Sigma.Method.LEFT), 64,
Sigma(&Func2, 512, -1.0L, 2.0L, Sigma.Method.LEFT),512) ;
writefln("\nSimpson Integral of FUNC2 =") ;
writefln("%12.9f (%3dstep).",
Sigma(&Func2, 512, -1.0L, 2.0L, Sigma.Method.SIMP),512) ;
}</pre>
Parts of the output:
<pre>Function(x) = 2 / (1 + 4x^2)
A = -1.000000, B = 2.000000, N = 4, h = 0.75
LeftRect = 2.456897
RightRect = 2.245132
MidRect = 2.496091
Trapezium = 2.351014
Simpson = 2.447732</pre>
* [http://math.furman.edu/~dcs/java/NumericalIntegration.html One can verifies his result with this applet]
=={{header|Java}}==
=={{header|Java}}==
The function in this example is assumed to be <tt>f(double x)</tt>.
The function in this example is assumed to be <tt>f(double x)</tt>.

Revision as of 03:04, 16 February 2008

Task
Numerical integration
You are encouraged to solve this task according to the task description, using any language you may know.

Write functions to calculate the definite integral of a function (f(x)) using rectangular (left, right, and midpoint), trapezium, and Simpson's methods. Your functions should take in the upper and lower bounds (a and b) and the number of approximations to make in that range (n). Assume that your example already has a function that gives values for f(x).

Simpson's method is defined by the following pseudocode:

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

loop on i from 0 to (n - 1)
 sum1 = sum1 + f(a + h * i + h / 2)

loop on i from 1 to (n - 1)
 sum2 = sum2 + f(a + h * i)

answer = (h / 6) * (f(a) + f(b) + 4 * sum1 + 2 * sum2)

What it will be doing is computing integrals for multiple quadratics (like the one shown in the wiki) and summing them.

Ada

This solution creates a generic package into which the function F(X) is passed during generic instantiation. The first part is the package specification. The second part is the package body.

generic
   with function F(X : Long_Float) return Long_Float;
package Integrate is
   function  Left_Rect(A, B, N : Long_Float) return Long_Float;
   function Right_Rect(A, B, N : Long_Float) return Long_Float;
   function   Mid_Rect(A, B, N : Long_Float) return Long_Float;
   function  Trapezium(A, B, N : Long_Float) return Long_Float;
   function    Simpson(A, B, N : Long_Float) return Long_Float;
end Integrate;
package body Integrate is

   ---------------
   -- Left_Rect --
   ---------------

   function Left_Rect (A, B, N : Long_Float) return Long_Float is
      H : constant Long_Float := (B - A) / N;
      Sum : Long_Float := 0.0;
      X : Long_Float := A;
   begin
      while X <= B - H loop
         Sum := Sum + (H * F(X));
         X := X + H;
      end loop;
      return Sum;
   end Left_Rect; 

   ----------------
   -- Right_Rect --
   ---------------- 

   function Right_Rect (A, B, N : Long_Float) return Long_Float is
      H : constant Long_Float := (B - A) / N;
      Sum : Long_Float := 0.0;
      X : Long_Float := A + H;
   begin
      while X <= B - H loop
         Sum := Sum + (H * F(X));
         X := X + H;
      end loop;
      return Sum;
   end Right_Rect;

   --------------
   -- Mid_Rect --
   --------------

   function Mid_Rect (A, B, N : Long_Float) return Long_Float is
      H : constant Long_Float := (B - A) / N;
      Sum : Long_Float := 0.0;
      X : Long_Float := A;
   begin
      while X <= B - H loop
         Sum := Sum + (H / 2.0) * (F(X) + F(X + H));
         X := X + H;
      end loop;
      return Sum;
   end Mid_Rect;

   ---------------
   -- Trapezium --
   --------------- 

   function Trapezium (A, B, N : Long_Float) return Long_Float is
      H : constant Long_Float := (B - A) / N;
      Sum : Long_Float := F(A) + F(B);
      X : Long_Float := 1.0;
   begin
      while X <= N - 1.0 loop
         Sum := Sum + 2.0 * F(A + X * (B - A) / N);
         X := X + 1.0;
      end loop;
      return (B - A) / (2.0 * N) * Sum;
   end Trapezium; 

   -------------
   -- Simpson --
   ------------- 

   function Simpson (A, B, N : Long_Float) return Long_Float is
      H : constant Long_Float := (B - A) / N;
      Sum1 : Long_Float := 0.0;
      Sum2 : Long_Float := 0.0;
      Limit : Integer := Integer(N) - 1;
   begin
      for I in 0..Limit loop
         Sum1 := Sum1 + F(A + H * Long_Float(I) + H / 2.0);
      end loop;
      for I in 1..Limit loop
         Sum2 := Sum2 + F(A + H * Long_Float(I));
      end loop;
      return H / 6.0 * (F(A) + F(B) + 4.0 * Sum1 + 2.0 * Sum2);
   end Simpson;

end Integrate;

ALGOL 68

MODE F = PROC(LONG REAL)LONG REAL;

###############
## left rect ##
###############

PROC left rect = (F f, LONG REAL a, b, INT n) LONG REAL:
BEGIN
   LONG REAL h= (b - a) / n;
   LONG REAL sum:= 0;
   LONG REAL x:= a;
   WHILE x <= b - h DO
      sum := sum + (h * f(x));
      x +:= h
   OD;
   sum
END # left rect #; 

#################
## right rect  ##
#################

PROC right rect = (F f, LONG REAL a, b, INT n) LONG REAL:
BEGIN
   LONG REAL h= (b - a) / n;
   LONG REAL sum:= 0;
   LONG REAL x:= a + h;
   WHILE x <= b - h DO
      sum := sum + (h * f(x));
      x +:= h
   OD;
   sum
END # right rect #;

###############
## mid rect  ##
###############

PROC mid rect = (F f, LONG REAL a, b, INT n) LONG REAL:
BEGIN
   LONG REAL h= (b - a) / n;
   LONG REAL sum:= 0;
   LONG REAL x:= a;
   WHILE x <= b - h DO
      sum := sum + (h / 2) * (f(x) + f(x + h));
      x +:= h
   OD;
   sum
END # mid rect #;

###############
## trapezium ##
############### 

PROC trapezium = (F f, LONG REAL a, b, INT n) LONG REAL:
BEGIN
   LONG REAL h= (b - a) / n;
   LONG REAL sum:= f(a) + f(b);
   LONG REAL x:= 1;
   WHILE x <= n - 1 DO
      sum := sum + 2 * f(a + x * h );
      x +:= 1
   OD;
   (b - a) / (2 * n) * sum
END # trapezium #; 

#############
## simpson ##
############# 

PROC simpson = (F f, LONG REAL a, b, INT n) LONG REAL:
BEGIN
   LONG REAL h= (b - a) / n;
   LONG REAL sum1:= 0;
   LONG REAL sum2:= 0;
   INT limit:= n - 1;
   FOR i FROM 0 TO limit DO
      sum1 := sum1 + f(a + h * LONG REAL(i) + h / 2)
   OD;
   FOR i FROM 1 TO limit DO
      sum2 +:= f(a + h * LONG REAL(i))
   OD;
   h / 6 * (f(a) + f(b) + 4 * sum1 + 2 * sum2)
END # simpson #;
SKIP

BASIC

Compiler: QuickBasic 4.5

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 - h 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 TO b - h STEP h
        sum = sum + (h / 2) * (f(x) + f(x + h))
     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 = sum + 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

C++

Due to their similarity, it makes sense to make the integration method a policy.

// 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)
  {
    switch(position)
    {
    case left:
      return f(x);
    case middle:
      return f(x+h/2);
    case right:
      return f(x+h);
    }
  }
private:
  position_type position;
};

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

class simpson
{
public:
  template<typename F, typename Float>
   double operator()(F f, Float x, Float h)
  {
    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());

D

The function f(x) is Func1/Func2 in this program.

module integrate ;
import std.stdio ;
import std.math ;

alias real function(real) realFn ;

class Sigma{
  int n ;
  real a, b , h ;
  realFn fn ; 
  string desc ;
  enum Method {LEFT = 0, RGHT, MIDD, TRAP, SIMP} ;
  static string[5] methodName = 
  ["LeftRect ", "RightRect", "MidRect  ", "Trapezium", "Simpson  "] ;
  static Sigma opCall() { 
    Sigma s = new Sigma() ; 
    return s ; 
  }
  static Sigma opCall(realFn f, int n, real a, real b) { 
    Sigma s = new Sigma(f, n, a, b) ; 
    return s ; 
  } 
  static real opCall(realFn f, int n, real a, real b, Method m) { 
    return Sigma(f,n,a,b).getSum(m) ;
  }
  private this() {} ;
  this(realFn f, int n, real a, real b) {
    setFunction(f) ;
    setStep(n) ;
    setRange(a,b) ;   
  } 
  Sigma opCall(Method m) { 
    return doSum(m) ; 
  }
  Sigma setFunction(realFn f) { 
    this.fn = f ; 
    return this ; 
  }
  Sigma setRange(real a, real b) { 
    this.a = a ; this.b = b ; 
    setInterval() ;
    return this ; 
  }
  Sigma setStep(int n) { 
    this.n = n ; 
    setInterval() ;
    return this ; 
  }
  Sigma setDesc(string d) { 
    this.desc = d ; 
    return this ; 
  }
  private void setInterval() { 
    this.h = (b - a) / n ; 
  }
  private real partSum(int i, Method m) {
    real x = a + h * i ;
    switch(m) {
      case Method.LEFT:
        return fn(x) ;
      case Method.RGHT:
        return fn(x + h) ;
      case Method.MIDD:
        return fn(x + h/2) ;
      case Method.TRAP:
        return (fn(x) + fn(x + h))/2 ;
      default:
    }
    //case SIMPSON:
    return (fn(x) + 4 * fn(x + h/2) + fn(x + h))/6 ;
  } 
  real getSum(Method m) {
    real sum = 0 ;
    for(int i = 0; i < n ; i++)
      sum += partSum(i, m) ;
    return sum * h ;
  } 
  Sigma doSum(Method m) {
    writefln("%10s = %9.6f", methodName[m], getSum(m)) ; 
    return this ; 
  }
  Sigma showSetting() {
    writefln("\n%s\nA = %9.6f, B = %9.6f, N = %s, h = %s", desc, a, b, n, h) ;
    return this ;
  } 
  Sigma doLeft() { return doSum(Method.LEFT) ; }
  Sigma doRight() { return doSum(Method.RGHT) ; }
  Sigma doMid() { return doSum(Method.MIDD) ; }
  Sigma doTrap() { return doSum(Method.TRAP) ; }
  Sigma doSimp() { return doSum(Method.SIMP) ; }
  Sigma doAll() {
    showSetting() ;
    doLeft() ; doRight() ; doMid() ; doTrap() ; doSimp() ;
    return this ; 
  }
}
real Func1(real x) {
  return cos(x) + sin(x)  ;
}
real Func2(real x) {
  return 2.0L/(1 + 4*x*x)  ;
}
void main() {
  // use as a re-usable and manageable object
  Sigma s = Sigma(&Func1, 10, -PI/2, PI/2).showSetting()
  .doLeft().doRight().doMid().doTrap()(Sigma.Method.SIMP) ;     
  s.setFunction(&Func2).setStep(4).setRange(-1.0L,2.0L) ; 
  s.setDesc("Function(x) = 2 / (1 + 4x^2)").doAll() ;
  // use as a single function call 
  writefln("\nLeftRect Integral of FUNC2 =") ;
  writefln("%12.9f (%3dstep)\n%12.9f (%3dstep)\n%12.9f (%3dstep).",
    Sigma(&Func2,   8, -1.0L, 2.0L, Sigma.Method.LEFT),  8,
    Sigma(&Func2,  64, -1.0L, 2.0L, Sigma.Method.LEFT), 64,
    Sigma(&Func2, 512, -1.0L, 2.0L, Sigma.Method.LEFT),512) ;
  writefln("\nSimpson Integral of FUNC2 =") ;
  writefln("%12.9f (%3dstep).",
    Sigma(&Func2, 512, -1.0L, 2.0L, Sigma.Method.SIMP),512) ;
}

Parts of the output:

Function(x) = 2 / (1 + 4x^2)
A = -1.000000, B =  2.000000, N = 4, h = 0.75
 LeftRect  =  2.456897
 RightRect =  2.245132
 MidRect   =  2.496091
 Trapezium =  2.351014
 Simpson   =  2.447732

Java

The function in this example is assumed to be f(double x).

public class Integrate{
   public static double leftRect(double a, double b, double n){
      double h = (b - a) / n;
      double sum = 0;
      for(double x = a;x <= b - h;x += h)
         sum += h * (f(x));
      return sum;
   }

   public static double rightRect(double a, double b, double n){
      double h = (b - a) / n;
      double sum = 0;
      for(double x = a + h;x <= b - h;x += h)
         sum += h * (f(x));
      return sum;
   }

   public static double midRect(double a, double b, double n){
      double h = (b - a) / n;
      double sum = 0;
      for(double x = a;x <= b - h;x += h)
         sum += (h / 2) * (f(x) + f(x + h));
      return sum;
   }

   public static double trap(double a, double b, double n){
      double h = (b - a) / n;
      double sum = f(a) + f(b);
      for(int i = 1;i <= n-1;i++)
         sum += 2 * f((a + i * h));
      return  h / 2 * sum;
   }

   public static double simpson(double a, double b, double n){
      double h = (b - a) / n;
      double sum1 = 0;
      double sum2 = 0;

      for(int i = 0;i < n;i++)
         sum1 += f(a + h * i + h / 2);

      for(int i = 1;i <= n - 1;i++)
         sum2 += f(a + h * i);

      return h / 6 * (f(a) + f(b) + 4 * sum1 + 2 * sum2);
   }
   //assume f(double x) elsewhere in the class
}

OCaml

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.

let left_rect f x _ =
  f x

let right_rect f x h =
  f (x +. h /. 2.)

let mid_rect f x h =
  f (x +. h)

let trapezium f x h =
  (f x +. f (x +. h)) /. 2.

let simpson f x h =
  (f x +. 4. *. f (x +. h /. 2.) +. f (x +. h)) /. 6.

let square x = x *. x

let rl = integrate square 0. 1. 10 left_rect
let rm = integrate square 0. 1. 10 mid_rect
let rr = integrate square 0. 1. 10 right_rect
let t = integrate square 0. 1. 10 trapezium
let s = integrate square 0. 1. 10 simpson