Skip to content

Commit

Permalink
Switch to Julia versions of pdf, cdf and invcdf.
Browse files Browse the repository at this point in the history
Also use Greek letters for parameters.  I can undo this if the consensus is against it.
  • Loading branch information
dmbates committed Jul 22, 2013
1 parent f8eccf6 commit 4cdc884
Showing 1 changed file with 47 additions and 25 deletions.
72 changes: 47 additions & 25 deletions src/univariate/normal.jl
Original file line number Diff line number Diff line change
@@ -1,48 +1,70 @@
immutable Normal <: ContinuousUnivariateDistribution
mean::Float64
std::Float64
function Normal(mu::Real, sd::Real)
sd > zero(sd) || error("std must be positive")
new(float64(mu), float64(sd))
μ::Float64
σ::Float64
function Normal(μ::Real, σ::Real)
σ > zero(σ) || error("std.dev. must be positive")

This comment has been minimized.

Copy link
@johnmyleswhite

johnmyleswhite Jul 22, 2013

Member

Why is this zero(σ)? Does this require type determination at run-time?

This comment has been minimized.

Copy link
@dmbates

dmbates Jul 22, 2013

Author Contributor

If I understand methods correctly it doesn't. The first time the constructor is called with say, Int and Int arguments a new method will be compiled. It is not a big deal but I don't see the need to convert the argument before checking it for positivity.

new(float64(μ), float64(σ))
end
end

Normal(mu::Real) = Normal(mu, 1.0)
Normal::Real) = Normal(float64(μ), 1.0)
Normal() = Normal(0.0, 1.0)

const Gaussian = Normal

@_jl_dist_2p Normal norm

entropy(d::Normal) = 0.5 * log(2.0 * pi) + 0.5 + log(d.std)
const Gaussian = Normal

begin
zval(d::Normal, x::Real) = (x - d.μ)/d.σ
xval(d::Normal, z::Real) = d.μ + d.σ * z

φ{T<:FloatingPoint}(z::T) = exp(-0.5*z*z)/√2π

This comment has been minimized.

Copy link
@simonbyrne

simonbyrne Jul 30, 2013

Member

@dmbates Is there a reason these are FloatingPoint, and not Real? I was surprised when I found I was getting different answers for integer values.

This comment has been minimized.

Copy link
@dmbates

dmbates Jul 30, 2013

Author Contributor

Different answers or an error? I suppose they could be defined for T<:Real as long as all the subsidiary function behave properly by promoting their arguments to a floating point type.

This comment has been minimized.

Copy link
@simonbyrne

simonbyrne Jul 30, 2013

Member

I noticed that cdf(Normal(), -10.0) was underflowing, but cdf(Normal(), -10) wasn't (as it was using the Rmath routines). I fixed it in 3f74be5. I think the division by sqrt(2) should convert any integers or rationals to floats.

pdf(d::Normal, x::FloatingPoint) = φ(zval(d,x))/d.σ

insupport(d::Normal, x::Number) = isreal(x) && isfinite(x)
logφ{T<:FloatingPoint}(z::T) = -0.5*(z*z + log2π)
logpdf(d::Normal, x::FloatingPoint) = logφ(zval(d,x)) - log(d.σ)

kurtosis(d::Normal) = 0.0
Φ{T<:FloatingPoint}(z::T) = 0.5 + 0.5*erf(z/√2)
cdf(d::Normal, x::FloatingPoint) = Φ(zval(d,x))

mean(d::Normal) = d.mean
Φc{T<:FloatingPoint}(z::T) = 0.5*erfc(z/√2)
ccdf(d::Normal, x::FloatingPoint) = Φc(zval(d,x))

median(d::Normal) = d.mean
Φinv{T<:FloatingPoint}(p::T) = 2 * erfinv(2p - 1)
quantile(d::Normal, p::FloatingPoint) = xval(d, Φinv(p))

function mgf(d::Normal, t::Real)
m, s = d.mean, d.std
return exp(t * m + 0.5 * s^t * t^2)
Φcinv{T<:FloatingPoint}(p::T) = 2 * erfcinv(2p)
cquantile(d::Normal, p::FloatingPoint) = xval(d, Φcinv(p))
end

function cf(d::Normal, t::Real)
m, s = d.mean, d.std
return exp(im * t * m - 0.5 * s^t * t^2)
for f in [pdf, logpdf, ccdf, cdf, quantile]
quote
$f(d::Normal, x::Integer) = $f(d, float64(x))
end
end

modes(d::Normal) = [d.mean]
entropy(d::Normal) = 0.5 * (log2π + 1.) + log(d.σ)

insupport(d::Normal, x::Real) = isfinite(x)

kurtosis(d::Normal) = 0.0

mean(d::Normal) = d.μ

median(d::Normal) = d.μ

mgf(d::Normal, t::Real) = exp(t * d.μ + 0.5 * d.σ^t * t^2)

cf(d::Normal, t::Real) = exp(im * t * d.μ - 0.5 * d.σ^t * t^2)

modes(d::Normal) = [d.μ]

rand(d::Normal) = d.mean + d.std * randn()
rand(d::Normal) = d.μ + d.σ * randn()

skewness(d::Normal) = 0.0

std(d::Normal) = d.std
std(d::Normal) = d.σ

var(d::Normal) = d.std^2
var(d::Normal) = d.σ^2

## Fit model

Expand All @@ -68,7 +90,7 @@ function suffstats{T<:Real}(::Type{Normal}, x::Array{T})
# compute ss
s2 = abs2(x[1] - m)
for i = 2:n
s2 += abs2(x[i] - m)
s2 += abs2(x[i] - m) # is there a reason this is not also @inbounds ?

This comment has been minimized.

Copy link
@lindahua

lindahua Jul 22, 2013

Contributor

Of course @inbounds can be placed here. I may take a look sometime later to add this macro to places that can benefit from it.

end

NormalStats(s, m, s2, n)
Expand Down

2 comments on commit 4cdc884

@johnmyleswhite
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I love these Greek characters as local variables (especially √2π), but it would be good to make sure others are onboard with using Greek letters for the field names.

@lindahua
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have now lean towards using greek letters (already used in MultivariateNormal) as field names. It makes the codes so much nicer to read.

Please sign in to comment.