dmd/compiler/test/runnable/integrate.d
2022-07-09 18:53:07 +02:00

166 lines
4.4 KiB
D

// PERMUTE_ARGS:
// REQUIRED_ARGS:
// NOTE: the shootout is under a BSD license
// The Great Computer Language Shootout
// http://shootout.alioth.debian.org/
//
// contributed by Sebastien Loisel
import core.stdc.math;
alias fl F;
struct fl
{
double a;
static fl opCall() { fl f; f.a = 0; return f; }
static fl opCall(fl v) { fl f; f.a = v.a; return f; }
void set(double x)
{
if(x==0) { a=0; return; }
int k=cast(int)log(fabs(x));
a=round(x*exp(-k+6.0))*exp(k-6.0);
}
static fl opCall(int x) { fl f; f.set(x); return f; }
static fl opCall(double x) { fl f; f.set(x); return f; }
fl opBinary(string op : "+")(fl y) { return fl(a+y.a); }
fl opOpAssign(string op : "+")(fl y) { this=(this)+y; return this; }
fl opBinary(string op : "-")(fl y) { return fl(a-y.a); }
fl opOpAssign(string op : "+")(fl y) { this=(this)-y; return this; }
fl opBinary(string op : "*")(fl y) { return fl(a*y.a); }
fl opBinary(string op : "/")(fl y) { return fl(a/y.a); }
fl opBinary(string op : "+")(int y) { return fl(a+y); }
fl opBinary(string op : "-")(int y) { return fl(a-y); }
fl opBinary(string op : "*")(int y) { return fl(a*y); }
fl opBinary(string op : "/")(int y) { return fl(a/y); }
fl opBinary(string op : "+")(double y) { return fl(a+y); }
fl opBinary(string op : "-")(double y) { return fl(a-y); }
fl opBinary(string op : "*")(double y) { return fl(a*y); }
fl opBinary(string op : "/")(double y) { return fl(a/y); }
}
struct ad
{
F x, dx;
static ad opCall() { ad t; t.x = F(0); t.dx = F(0); return t; }
static ad opCall(int y) { ad t; t.x = F(y); t.dx = F(0); return t; }
static ad opCall(F y) { ad t; t.x = y; t.dx = F(0); return t; }
static ad opCall(F X, F DX) { ad t; t.x = X; t.dx = DX; return t; }
ad opBinary(string op : "+")(ad y) { return ad(x+y.x,dx+y.dx); }
ad opBinary(string op : "-")(ad y) { return ad(x-y.x,dx-y.dx); }
ad opBinary(string op : "*")(ad y) { return ad(x*y.x,dx*y.x+x*y.dx); }
ad opBinary(string op : "/")(ad y) { return ad(x/y.x,(dx*y.x-x*y.dx)/(y.x*y.x)); }
ad opBinary(string op : "*")(F v) { return ad(x*v,dx*v); }
ad opBinary(string op : "+")(F v) { return ad(x+v,dx); }
}
F sqr(F x) { return x * x; }
ad sqr(ad x) { return x * x; }
F pow(F x, int i)
{
if(i < 1) return F(1);
if(i & 1) if(i == 1) return x; else return x * pow(x,i-1);
return sqr(pow(x,i/2));
}
ad pow(ad x, int i)
{
if(i < 1) return ad(1);
if(i & 1) if(i == 1) return x; else return x * pow(x,i-1);
return sqr(pow(x,i/2));
}
F rat(F x)
{
F t = (x * F(2) + pow(x,2) * F(3) + pow(x,6) * F(7) + pow(x,11) * F(5) + F(1))
/ (x * F(5) - pow(x,3) * F(6) - pow(x,7) * F(3) + F(2));
return t;
}
ad rat(ad x)
{
ad t = (x * ad(2) + pow(x,2) * ad(3) + pow(x,6) * ad(7) + pow(x,11) * ad(5) + ad(1))
/ (x * ad(5) - pow(x,3) * ad(6) - pow(x,7) * ad(3) + ad(2));
return t;
}
F newton(F x0, int n, trapezoid_method_rooter g)
{
for(int i=0 ; i<n; i++)
{
ad val = g( ad(x0,F(1)) ); // ad = trapezoid_method_rooter(ad);
//**
x0 = x0 - val.x / val.dx;
/+
F t0 = val.x;
F t1 = val.dx;
x0 = x0 - t0 / t1;
+/
}
return x0;
}
struct trapezoid_method_rooter
{
sqrintegrand g;
ad g0;
F y0, t0, t1;
trapezoid_method_rooter opCall(sqrintegrand G, F Y0, F T0, F T1)
{
g = G;
y0 = Y0;
t0 = T0;
t1 = T1;
g0 = G(T0,Y0); // ad = sqr/ratintegrand(float,float);
return this;
}
ad opCall(ad y1)
{
return (g(ad(t1),y1) + g0) * ((t1-t0)/F(2)) + y0 - y1; // ad = sqr/ratintegrand(ad,ad);
}
}
F trapezoid_method(F t0, F dt, F y0, sqrintegrand g, int numsteps)
{
for(int i = 0; i < numsteps; i++)
{
trapezoid_method_rooter solver;
y0 = newton(y0,10,solver(g,y0,t0,t0+dt));
t0 = t0 + dt;
}
return y0;
}
struct sqrintegrand
{
ad opCall(F t, F y) { return ad(sqr(y)); }
ad opCall(ad t, ad y) { return sqr(y); }
}
struct ratintegrand
{
ad opCall(F t, F y) { return ad(rat(y) - t); }
ad opCall(ad t, ad y) { return rat(y) - t; }
}
auto integrate_functions(F x0, int n)
{
sqrintegrand i1;
return trapezoid_method(F(1), F(1) / F(n), x0, i1 ,n).a;
}
int main(string[] args)
{
int N = 50;
const res = integrate_functions(F(0.02),N);
assert(0.01999 < res);
assert(res < 0.02);
return 0;
}