123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117 |
|
/*******************************************************************************
copyright: Copyright (c) 2008. Fawzi Mohamed
license: BSD style: $(LICENSE)
version: Initial release: July 2008
author: Fawzi Mohamed
*******************************************************************************/
module tango.math.random.NormalSource;
private import Integer = tango.text.convert.Integer;
import tango.math.Math:exp,sqrt,log,PI;
import tango.math.ErrorFunction:erfc;
import tango.math.random.Ziggurat;
import tango.core.Traits: isRealType;
/// class that returns gaussian (normal) distributed numbers (f=exp(-0.5*x*x)/sqrt(2*pi))
class NormalSource(RandG,T){
static assert(isRealType!(T),T.stringof~" not acceptable, only floating point variables supported");
/// probability distribution (non normalized, should be divided by sqrt(2*PI))
static real probDensityF(real x){ return exp(-0.5L*x*x); }
/// inverse probability distribution
static real invProbDensityF(real x){ return sqrt(-2.0L*log(x)); }
/// complement of the cumulative density distribution (integral x..infinity probDensityF)
static real cumProbDensityFCompl(real x){ return sqrt(0.5L*PI)*erfc(x/sqrt(2.0L));/*normalDistributionCompl(x);*/ }
/// tail for normal distribution
static T tailGenerator(RandG r, T dMin, int iNegative)
{
T x, y;
do
{
x = -log(r.uniform!(T)()) / dMin;
y = -log(r.uniform!(T)());
} while (y+y < x * x);
return (iNegative ?(-x - dMin):(dMin + x));
}
alias Ziggurat!(RandG,T,probDensityF,tailGenerator,true) SourceT;
/// internal source of normal numbers
SourceT source;
/// initializes the probability distribution
this(RandG r){
source=SourceT.create!(invProbDensityF,cumProbDensityFCompl)(r,0xe.9dda4104d699791p-2L);
}
/// chainable call style initialization of variables (thorugh a call to randomize)
NormalSource opCall(U,S...)(ref U a,S args){
randomize(a,args);
return this;
}
/// returns a normal distribued number
final T getRandom(){
return source.getRandom();
}
/// returns a normal distribued number with the given sigma (standard deviation)
final T getRandom(T sigma){
return sigma*source.getRandom();
}
/// returns a normal distribued number with the given sigma (standard deviation) and mu (average)
final T getRandom(T sigma, T mu){
return mu+sigma*source.getRandom();
}
/// initializes a variable with normal distribued number and returns it
U randomize(U)(ref U a){
return source.randomize(a);
}
/// initializes a variable with normal distribued number with the given sigma and returns it
U randomize(U,V)(ref U a,V sigma){
return source.randomizeOp((T x){ return x*cast(T)sigma; },a);
}
/// initializes a variable with normal distribued numbers with the given sigma and mu and returns it
U randomize(U,V,S)(ref U el,V sigma, S mu){
return source.randomizeOp((T x){ return x*cast(T)sigma+cast(T)mu; },a);
}
/// initializes the variable with the result of mapping op on the random numbers (of type T)
U randomizeOp(U,S)(scope S delegate(T) op,ref U a){
return source.randomizeOp(op,a);
}
/// normal distribution with different default sigma and mu
/// f=exp(-x*x/(2*sigma^2))/(sqrt(2 pi)*sigma)
struct NormalDistribution{
T sigma,mu;
NormalSource source;
/// constructor
static NormalDistribution create(NormalSource source,T sigma,T mu){
NormalDistribution res;
res.source=source;
res.sigma=sigma;
res.mu=mu;
return res;
}
/// chainable call style initialization of variables (thorugh a call to randomize)
NormalDistribution opCall(U,S...)(ref U a,S args){
randomize(a,args);
return this;
}
/// returns a single number
T getRandom(){
return mu+sigma*source.getRandom();
}
/// initialize a
U randomize(U)(ref U a){
T op(T x){return mu+sigma*x; }
return source.randomizeOp(&op,a);
}
/// initialize a (let s and m have different types??)
U randomize(U,V)(ref U a,V s){
T op(T x){return mu+(cast(T)s)*x; }
return source.randomizeOp(&op,a);
}
/// initialize a (let s and m have different types??)
U randomize(U,V,S)(ref U a,V s, S m){
T op(T x){return (cast(T)m)+(cast(T)s)*x; }
return source.randomizeOp(&op,a);
}
}
/// returns a normal distribution with a non-default sigma/mu
NormalDistribution normalD(T sigma=cast(T)1,T mu=cast(T)0){
return NormalDistribution.create(this,sigma,mu);
}
}
|