Another update from ingydotnet^djgoku

This commit is contained in:
Ingy döt Net 2015-11-18 06:14:39 +00:00
parent 91df62d461
commit 948b86eafa
7604 changed files with 108452 additions and 22726 deletions

View file

@ -19,8 +19,8 @@ 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))
FOR x = a + h / 2 TO b - h / 2 STEP h
sum = sum + h * (f(x))
NEXT x
midRect = sum
END FUNCTION
@ -40,7 +40,7 @@ FUNCTION simpson(a, b, n)
sum2 = 0
FOR i = 0 TO n-1
sum1 = sum + f(a + h * i + h / 2)
sum1 = sum1 + f(a + h * i + h / 2)
NEXT i
FOR i = 1 TO n - 1

View file

@ -0,0 +1,36 @@
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)

View file

@ -39,35 +39,35 @@ var methods = []method{
}
func rectLeft(t spec) float64 {
parts := make([]float64, t.n)
var a adder
r := t.upper - t.lower
nf := float64(t.n)
x0 := t.lower
for i := range parts {
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)
parts[i] = t.f(x0) * (x1 - x0)
a.add(t.f(x0) * (x1 - x0))
x0 = x1
}
return sum(parts)
return a.total()
}
func rectRight(t spec) float64 {
parts := make([]float64, t.n)
var a adder
r := t.upper - t.lower
nf := float64(t.n)
x0 := t.lower
for i := range parts {
for i := 0; i < t.n; i++ {
x1 := t.lower + float64(i+1)*r/nf
parts[i] = t.f(x1) * (x1 - x0)
a.add(t.f(x1) * (x1 - x0))
x0 = x1
}
return sum(parts)
return a.total()
}
func rectMid(t spec) float64 {
parts := make([]float64, t.n)
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
@ -77,80 +77,72 @@ func rectMid(t spec) float64 {
// 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 := range parts {
for i := 0; i < t.n; i++ {
x1 := t.lower + (float64(i)+.5)*r/nf
parts[i] = t.f(x1) * (x1 - x0)
a.add(t.f(x1) * (x1 - x0))
x0 = x1
}
return sum(parts)
return a.total()
}
func trap(t spec) float64 {
parts := make([]float64, t.n)
var a adder
r := t.upper - t.lower
nf := float64(t.n)
x0 := t.lower
f0 := t.f(x0)
for i := range parts {
for i := 0; i < t.n; i++ {
x1 := t.lower + float64(i+1)*r/nf
f1 := t.f(x1)
parts[i] = (f0 + f1) * .5 * (x1 - x0)
a.add((f0 + f1) * .5 * (x1 - x0))
x0, f0 = x1, f1
}
return sum(parts)
return a.total()
}
func simpson(t spec) float64 {
parts := make([]float64, 2*t.n+1)
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
parts[0] = t.f(t.lower) * dx0
parts[1] = t.f(t.lower+dx0*.5) * dx0 * 4
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
parts[2*i] = t.f(x0) * dx * 2
parts[2*i+1] = t.f(xmid) * dx * 4
a.add(t.f(x0) * dx * 2)
a.add(t.f(xmid) * dx * 4)
x0 = x1
}
parts[2*t.n] = t.f(t.upper) * dx0
return sum(parts) / 6
a.add(t.f(t.upper) * dx0)
return a.total() / 6
}
// sum a list of numbers avoiding loss of precision
func sum(v []float64) float64 {
if len(v) == 0 {
return 0
var a adder
for _, e := range v {
a.add(e)
}
var parts []float64
for _, x := range v {
var i int
for _, p := range parts {
sum := p + x
var err float64
if math.Abs(x) < math.Abs(p) {
err = x - (sum - p)
} else {
err = p - (sum - x)
}
if err != 0 {
parts[i] = err
i++
}
x = sum
}
parts = append(parts[:i], x)
}
var sum float64
for _, x := range parts {
sum += x
}
return sum
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() {

View file

@ -1,21 +1,21 @@
sub leftrect(&f, $a, $b, $n) {
my $h = ($b - $a) / $n;
$h * [+] do f($_) for $a, *+$h ... $b-$h;
$h * [+] do f($_) for $a, $a+$h ... $b-$h;
}
sub rightrect(&f, $a, $b, $n) {
my $h = ($b - $a) / $n;
$h * [+] do f($_) for $a+$h, *+$h ... $b;
$h * [+] do f($_) for $a+$h, $a+$h+$h ... $b;
}
sub midrect(&f, $a, $b, $n) {
my $h = ($b - $a) / $n;
$h * [+] do f($_) for $a+$h/2, *+$h ... $b-$h/2;
$h * [+] do f($_) for $a+$h/2, $a+$h+$h/2 ... $b-$h/2;
}
sub trapez(&f, $a, $b, $n) {
my $h = ($b - $a) / $n;
$h / 2 * [+] f($a), f($b), do f($_) * 2 for $a+$h, *+$h ... $b-$h;
$h / 2 * [+] f($a), f($b), |do f($_) * 2 for $a+$h, $a+$h+$h ... $b-$h;
}
sub simpsons(&f, $a, $b, $n) {
@ -33,7 +33,7 @@ sub simpsons(&f, $a, $b, $n) {
sub tryem($f, $a, $b, $n, $exact) {
say "\n$f\n in [$a..$b] / $n";
eval "my &f = $f;
EVAL "my &f = $f;
say ' exact result: ', $exact;
say ' rectangle method left: ', leftrect &f, $a, $b, $n;
say ' rectangle method right: ', rightrect &f, $a, $b, $n;
@ -46,6 +46,6 @@ tryem '{ $_ ** 3 }', 0, 1, 100, 0.25;
tryem '1 / *', 1, 100, 1000, log(100);
tryem '{$_}', 0, 5_000, 10_000, 12_500_000;
tryem '*.self', 0, 5_000, 5_000_000, 12_500_000;
tryem '{$_}', 0, 6_000, 12_000, 18_000_000;
tryem '*.self', 0, 6_000, 6_000_000, 18_000_000;

View file

@ -3,7 +3,7 @@
exact result: 0.25
rectangle method left: 0.245025
rectangle method right: 0.255025
rectangle method mid: 0.2499875
rectangle method mid: 0.249988
composite trapezoidal rule: 0.250025
quadratic simpsons rule: 0.25
@ -16,20 +16,20 @@ composite trapezoidal rule: 0.250025
composite trapezoidal rule: 4.60598605751468
quadratic simpsons rule: 4.60517038495714
{$_}
in [0..5000] / 10000
*.self
in [0..5000] / 5000000
exact result: 12500000
rectangle method left: 12498750
rectangle method right: 12501250
rectangle method left: 12499997.5
rectangle method right: 12500002.5
rectangle method mid: 12500000
composite trapezoidal rule: 12500000
quadratic simpsons rule: 12500000
{$_}
in [0..6000] / 12000
*.self
in [0..6000] / 6000000
exact result: 18000000
rectangle method left: 17998500
rectangle method right: 18001500
rectangle method left: 17999997
rectangle method right: 18000003
rectangle method mid: 18000000
composite trapezoidal rule: 18000000
quadratic simpsons rule: 18000000

View file

@ -1,59 +1,47 @@
/*REXX program numerically integrates using five different methods. */
numeric digits 20 /*use twenty digits precision. */
/*REXX program does numerical integration using five different algorithms.*/
numeric digits 20 /*use twenty decimal digits precision. */
do test=1 for 4 /*perform the test suite. */
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=5000000; end
say
say center('test' test,79,'') /*display a header for the test. */
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 ' trapezoid('L","H','i") = " trapezoid(L,H,i)
end /*test*/
exit /*stick a fork in it, we're done.*/
/*──────────────────────────────────LEFT_RECT subroutine────────────────*/
left_rect: procedure expose test; parse arg a,b,n; h=(b-a)/n
sum=0
do x=a by h for n
sum=sum+f(x)
end /*x*/
return sum*h
/*──────────────────────────────────MIDPOINT_RECT subroutine────────────*/
midpoint_rect: procedure expose test; parse arg a,b,n; h=(b-a)/n
sum=0
do x=a+h/2 by h for n
sum=sum+f(x)
end /*x*/
return sum*h
/*──────────────────────────────────RIGHT_RECT subroutine───────────────*/
right_rect: procedure expose test; parse arg a,b,n; h=(b-a)/n
sum=0
do x=a+h by h for n
sum=sum+f(x)
end /*x*/
return sum*h
/*──────────────────────────────────SIMPSON subroutine──────────────────*/
simpson: procedure expose test; parse arg a,b,n; h=(b-a)/n
sum1=f(a+h/2)
sum2=0; do x=1 to n-1
sum1=sum1+f(a+h*x+h*.5)
sum2=sum2+f(a+x*h)
end /*x*/
do test=1 for 4 /*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=5000000; end
say
say center('test' test,65,'') /*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: if test==1 then return arg(1)**3
if test==2 then return 1/arg(1)
return arg(1)
/*────────────────────────────────────────────────────────────────────────────*/
left_rect: procedure expose test; parse arg a,b,n; h=(b-a)/n
$=0
do x=a by h for n; $=$+f(x); end /*x*/
return $*h/1 /*return the number with no trailing 0s*/
/*────────────────────────────────────────────────────────────────────────────*/
midpoint_rect: procedure expose test; parse arg a,b,n; h=(b-a)/n
$=0
do x=a+h/2 by h for n; $=$+f(x); end /*x*/
return $*h/1 /*return the number with no trailing 0s*/
/*────────────────────────────────────────────────────────────────────────────*/
right_rect: procedure expose test; parse arg a,b,n; h=(b-a)/n
$=0
do x=a+h by h for n; $=$+f(x); end /*x*/
return $*h/1 /*return the number with no trailing 0s*/
/*────────────────────────────────────────────────────────────────────────────*/
Simpson: procedure expose test; parse arg a,b,n; h=(b-a)/n
$=f(a+h/2)
@=0; do x=1 for n-1; $=$+f(a+h*x+h*.5); @=@+f(a+x*h); end /*x*/
return h*(f(a)+f(b)+4*sum1+2*sum2)/6
/*──────────────────────────────────TRAPEZOID subroutine────────────────*/
trapezoid: procedure expose test; parse arg a,b,n; h=(b-a)/n
sum=0
do x=a to b by h
sum=sum+h*(f(x)+f(x+h))*.5
end /*x*/
return sum
/*──────────────────────────────────F subroutine────────────────────────*/
f: procedure expose test; parse arg z
if test==1 then return z**3
if test==2 then return 1/z
return z
return h*(f(a) + f(b) + 4*$ + 2*@)/6 /*return the number with no trailing 0s*/
/*────────────────────────────────────────────────────────────────────────────*/
trapezium: procedure expose test; parse arg a,b,n; h=(b-a)/n
$=0
do x=a by h for n; $=$+(f(x)+f(x+h)); end /*x*/
return $*h/2 /*return the number with no trailing 0s*/

View file

@ -0,0 +1,20 @@
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));
}