Skip to content

Commit 04d8459

Browse files
authored
Merge pull request #718 from HugoMVale/stats-distribution-normal
Improve doc + examples of `stdlib_stats_distribution_normal`
2 parents 9630cc5 + a52a088 commit 04d8459

File tree

5 files changed

+123
-86
lines changed

5 files changed

+123
-86
lines changed

doc/specs/stdlib_stats_distribution_normal.md

Lines changed: 24 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,16 @@ Experimental
1414

1515
### Description
1616

17-
A normal continuous random variate distribution, also known as Gaussian, or Gauss or Laplace-Gauss distribution. The location `loc` specifies the mean or expectation. The `scale` specifies the standard deviation.
17+
A normal continuous random variate distribution, also known as Gaussian, or Gauss or Laplace-Gauss distribution. The location `loc` specifies the mean or expectation ($\mu$). The `scale` specifies the standard deviation ($\sigma$).
1818

19-
Without argument the function returns a standard normal distributed random variate N(0,1).
19+
Without argument, the function returns a standard normal distributed random variate $N(0,1)$.
2020

21-
With two arguments, the function returns a normal distributed random variate N(loc, scale^2). For complex arguments, the real and imaginary parts are independent of each other.
21+
With two arguments, the function returns a normal distributed random variate $N(\mu=\text{loc}, \sigma^2=\text{scale}^2)$. For complex arguments, the real and imaginary parts are independent of each other.
2222

23-
With three arguments, the function returns a rank one array of normal distributed random variates.
23+
With three arguments, the function returns a rank-1 array of normal distributed random variates.
2424

25-
Note: the algorithm used for generating normal random variates is fundamentally limited to double precision.
25+
@note
26+
The algorithm used for generating exponential random variates is fundamentally limited to double precision.[^1]
2627

2728
### Syntax
2829

@@ -36,15 +37,15 @@ Elemental function (passing both `loc` and `scale`).
3637

3738
`loc`: optional argument has `intent(in)` and is a scalar of type `real` or `complex`.
3839

39-
`scale`: optional argument has `intent(in)` and is a scalar of type `real` or `complex`.
40+
`scale`: optional argument has `intent(in)` and is a positive scalar of type `real` or `complex`.
4041

4142
`array_size`: optional argument has `intent(in)` and is a scalar of type `integer`.
4243

4344
`loc` and `scale` arguments must be of the same type.
4445

4546
### Return value
4647

47-
The result is a scalar or rank one array, with a size of `array_size`, and as the same type of `scale` and `loc`.
48+
The result is a scalar or rank-1 array, with a size of `array_size`, and the same type as `scale` and `loc`. If `scale` is non-positive, the result is `NaN`.
4849

4950
### Example
5051

@@ -62,11 +63,11 @@ Experimental
6263

6364
The probability density function (pdf) of the single real variable normal distribution:
6465

65-
$$f(x) = \frac{1}{\sigma \sqrt{2}} e^{-\frac{1}{2}(\frac{x-\mu}{\sigma})^{2}}$$
66+
$$f(x) = \frac{1}{\sigma \sqrt{2}} \exp{\left[-\frac{1}{2}\left(\frac{x-\mu}{\sigma}\right)^{2}\right]}$$
6667

67-
For complex varible (x + y i) with independent real x and imaginary y parts, the joint probability density function is the product of corresponding marginal pdf of real and imaginary pdf (ref. "Probability and Random Processes with Applications to Signal Processing and Communications", 2nd ed., Scott L. Miller and Donald Childers, 2012, p.197):
68+
For a complex varible $z=(x + y i)$ with independent real $x$ and imaginary $y$ parts, the joint probability density function is the product of the the corresponding real and imaginary marginal pdfs:[^2]
6869

69-
$$f(x + y \mathit{i}) = f(x) f(y) = \frac{1}{2\sigma_{x}\sigma_{y}} e^{-\frac{1}{2}[(\frac{x-\mu}{\sigma_{x}})^{2}+(\frac{y-\nu}{\sigma_{y}})^{2}]}$$
70+
$$f(x + y \mathit{i}) = f(x) f(y) = \frac{1}{2\sigma_{x}\sigma_{y}} \exp{\left[-\frac{1}{2}\left(\left(\frac{x-\mu_x}{\sigma_{x}}\right)^{2}+\left(\frac{y-\mu_y}{\sigma_{y}}\right)^{2}\right)\right]}$$
7071

7172
### Syntax
7273

@@ -82,13 +83,13 @@ Elemental function
8283

8384
`loc`: has `intent(in)` and is a scalar of type `real` or `complex`.
8485

85-
`scale`: has `intent(in)` and is a scalar of type `real` or `complex`.
86+
`scale`: has `intent(in)` and is a positive scalar of type `real` or `complex`.
8687

8788
All three arguments must have the same type.
8889

8990
### Return value
9091

91-
The result is a scalar or an array, with a shape conformable to arguments, and as the same type of input arguments.
92+
The result is a scalar or an array, with a shape conformable to the arguments, and the same type as the input arguments. If `scale` is non-positive, the result is `NaN`.
9293

9394
### Example
9495

@@ -106,11 +107,13 @@ Experimental
106107

107108
Cumulative distribution function of the single real variable normal distribution:
108109

109-
$$F(x)=\frac{1}{2}\left [ 1+erf(\frac{x-\mu}{\sigma \sqrt{2}}) \right ]$$
110+
$$F(x) = \frac{1}{2}\left [ 1+\text{erf}\left(\frac{x-\mu}{\sigma \sqrt{2}}\right) \right ]$$
110111

111-
For the complex variable (x + y i) with independent real x and imaginary y parts, the joint cumulative distribution function is the product of corresponding marginal cdf of real and imaginary cdf (ref. "Probability and Random Processes with Applications to Signal Processing and Communications", 2nd ed., Scott L. Miller and Donald Childers, 2012, p.197):
112+
For the complex variable $z=(x + y i)$ with independent real $x$ and imaginary $y$ parts, the joint cumulative distribution function is the product of the corresponding real and imaginary marginal cdfs:[^2]
112113

113-
$$F(x+y\mathit{i})=F(x)F(y)=\frac{1}{4} [1+erf(\frac{x-\mu}{\sigma_{x} \sqrt{2}})] [1+erf(\frac{y-\nu}{\sigma_{y} \sqrt{2}})]$$
114+
$$ F(x+y\mathit{i})=F(x)F(y)=\frac{1}{4} \
115+
\left[ 1+\text{erf}\left(\frac{x-\mu_x}{\sigma_x \sqrt{2}}\right) \right] \
116+
\left[ 1+\text{erf}\left(\frac{y-\mu_y}{\sigma_y \sqrt{2}}\right) \right] $$
114117

115118
### Syntax
116119

@@ -126,16 +129,20 @@ Elemental function
126129

127130
`loc`: has `intent(in)` and is a scalar of type `real` or `complex`.
128131

129-
`scale`: has `intent(in)` and is a scalar of type `real` or `complex`.
132+
`scale`: has `intent(in)` and is a positive scalar of type `real` or `complex`.
130133

131134
All three arguments must have the same type.
132135

133136
### Return value
134137

135-
The result is a scalar or an array, with a shape conformable to arguments, as the same type of input arguments.
138+
The result is a scalar or an array, with a shape conformable to the arguments, and the same type as the input arguments. If `scale` is non-positive, the result is `NaN`.
136139

137140
### Example
138141

139142
```fortran
140143
{!example/stats_distribution_normal/example_norm_cdf.f90!}
141144
```
145+
146+
[^1] Marsaglia, George, and Wai Wan Tsang. "The ziggurat method for generating random variables." _Journal of statistical software_ 5 (2000): 1-7.
147+
148+
[^2] Miller, Scott, and Donald Childers. _Probability and random processes: With applications to signal processing and communications_. Academic Press, 2012 (p. 197).
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
ADD_EXAMPLE(normal_pdf)
22
ADD_EXAMPLE(normal_rvs)
3-
ADD_EXAMPLE(norm_cdf)
3+
ADD_EXAMPLE(normal_cdf)

example/stats_distribution_normal/example_norm_cdf.f90

Lines changed: 0 additions & 45 deletions
This file was deleted.
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
program example_normal_cdf
2+
use stdlib_random, only: random_seed
3+
use stdlib_stats_distribution_normal, only: norm_cdf => cdf_normal, &
4+
norm => rvs_normal
5+
6+
implicit none
7+
real, dimension(2, 3, 4) :: x, mu, sigma
8+
real :: xsum
9+
complex :: loc, scale
10+
integer :: seed_put, seed_get, i
11+
12+
seed_put = 1234567
13+
call random_seed(seed_put, seed_get)
14+
15+
! standard normal cumulative probability at x=0.0
16+
print *, norm_cdf(0.0, 0.0, 1.0)
17+
! 0.500000000
18+
19+
! cumulative probability at x=2.0 with mu=-1.0 sigma=2.0
20+
print *, norm_cdf(2.0, -1.0, 2.0)
21+
! 0.933192849
22+
23+
! cumulative probability at x=1.0 with mu=1.0 and sigma=-1.0 (out of range)
24+
print *, norm_cdf(1.0, 1.0, -1.0)
25+
! NaN
26+
27+
! standard normal random variates array
28+
x = reshape(norm(0.0, 1.0, 24), [2, 3, 4])
29+
30+
! standard normal cumulative array
31+
mu(:, :, :) = 0.0
32+
sigma(:, :, :) = 1.0
33+
print *, norm_cdf(x, mu, sigma)
34+
! 0.713505626 0.207069695 0.486513376 0.424511284 0.587328553
35+
! 0.335559726 0.401470929 0.806552052 0.866687536 0.371323735
36+
! 0.866228044 0.898046613 0.198435277 0.141147852 0.681565762
37+
! 0.206268221 0.627057910 0.580759525 0.190364420 7.27325380E-02
38+
! 7.08068311E-02 0.728241026 0.522919059 0.390097380
39+
40+
! cumulative probability array where sigma<=0.0 for certain elements
41+
print *, norm_cdf([1.0, 1.0, 1.0], [1.0, 1.0, 1.0], [1.0, 0.0, -1.0])
42+
! 0.500000000 NaN NaN
43+
44+
! `cdf_normal` is pure and, thus, can be called concurrently
45+
xsum = 0.0
46+
do concurrent (i=1:size(x,3))
47+
xsum = xsum + sum(norm_cdf(x(:,:,i), mu(:,:,i), sigma(:,:,i)))
48+
end do
49+
print *, xsum
50+
! 11.3751936
51+
52+
! complex normal cumulative distribution at x=(0.5,-0.5) with real part of
53+
! mu=1.0, sigma=0.5 and imaginary part of mu=0.0, sigma=1.0
54+
loc = (1.0, 0.0)
55+
scale = (0.5, 1.0)
56+
print *, norm_cdf((0.5, -0.5), loc, scale)
57+
! 4.89511043E-02
58+
59+
end program example_normal_cdf
60+

example/stats_distribution_normal/example_normal_pdf.f90

Lines changed: 38 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,41 +4,56 @@ program example_normal_pdf
44
norm => rvs_normal
55

66
implicit none
7-
real :: x(3, 4, 5), a(3, 4, 5), b(3, 4, 5)
7+
real, dimension(3, 4, 5) :: x, mu, sigma
8+
real :: xsum
89
complex :: loc, scale
9-
integer :: seed_put, seed_get
10+
integer :: seed_put, seed_get, i
1011

1112
seed_put = 1234567
1213
call random_seed(seed_put, seed_get)
1314

14-
print *, norm_pdf(1.0, 0., 1.) !a probability density at 1.0 in standard normal
15-
16-
! 0.241970733
15+
! probability density at x=1.0 in standard normal
16+
print *, norm_pdf(1.0, 0., 1.)
17+
! 0.241970733
1718

19+
! probability density at x=2.0 with mu=-1.0 and sigma=2.0
1820
print *, norm_pdf(2.0, -1.0, 2.0)
19-
!a probability density at 2.0 with mu=-1.0 sigma=2.0
21+
! 6.47588000E-02
2022

21-
!6.47588000E-02
23+
! probability density at x=1.0 with mu=1.0 and sigma=-1.0 (out of range)
24+
print *, norm_pdf(1.0, 1.0, -1.0)
25+
! NaN
2226

27+
! standard normal random variates array
2328
x = reshape(norm(0.0, 1.0, 60), [3, 4, 5])
24-
! standard normal random variates array
25-
26-
a(:, :, :) = 0.0
27-
b(:, :, :) = 1.0
28-
print *, norm_pdf(x, a, b) ! standard normal probability density array
29-
30-
! 0.340346158 0.285823315 0.398714304 0.391778737 0.389345556
31-
! 0.364551932 0.386712372 0.274370432 0.215250477 0.378006011
32-
! 0.215760440 0.177990928 0.278640658 0.223813817 0.356875211
33-
! 0.285167664 0.378533930 0.390739858 0.271684974 0.138273031
34-
! 0.135456234 0.331718773 0.398283750 0.383706540
35-
29+
30+
! standard normal probability density array
31+
mu(:, :, :) = 0.0
32+
sigma(:, :, :) = 1.0
33+
print *, norm_pdf(x, mu, sigma)
34+
! 0.340346158 0.285823315 0.398714304 0.391778737 0.389345556
35+
! 0.364551932 0.386712372 0.274370432 0.215250477 0.378006011
36+
! 0.215760440 0.177990928 0.278640658 0.223813817 0.356875211
37+
! 0.285167664 0.378533930 0.390739858 0.271684974 0.138273031
38+
! 0.135456234 0.331718773 0.398283750 0.383706540
39+
40+
! probability density array where sigma<=0.0 for certain elements
41+
print *, norm_pdf([1.0, 1.0, 1.0], [1.0, 1.0, 1.0], [1.0, 0.0, -1.0])
42+
! 0.398942292 NaN NaN
43+
44+
! `pdf_normal` is pure and, thus, can be called concurrently
45+
xsum = 0.0
46+
do concurrent (i=1:size(x,3))
47+
xsum = xsum + sum(norm_pdf(x(:,:,i), mu(:,:,i), sigma(:,:,i)))
48+
end do
49+
print *, xsum
50+
! 18.0754433
51+
52+
! complex normal probability density function at x=(1.5,1.0) with real part
53+
! of mu=1.0, sigma=1.0 and imaginary part of mu=-0.5, sigma=2.0
3654
loc = (1.0, -0.5)
3755
scale = (1.0, 2.)
3856
print *, norm_pdf((1.5, 1.0), loc, scale)
39-
! a complex normal probability density function at (1.5,1.0) with real part
40-
! of mu=1.0, sigma=1.0 and imaginary part of mu=-0.5, sigma=2.0
41-
42-
! 5.30100204E-02
57+
! 5.30100204E-02
4358

4459
end program example_normal_pdf

0 commit comments

Comments
 (0)