File Coverage

blib/lib/Math/Random/Normal/Leva.pm
Criterion Covered Total %
statement 22 26 84.6
branch 4 6 66.6
condition 4 5 80.0
subroutine 4 5 80.0
pod 2 2 100.0
total 36 44 81.8


line stmt bran cond sub pod time code
1             package Math::Random::Normal::Leva;
2 2     2   40518 use strict;
  2         4  
  2         72  
3 2     2   7 use warnings;
  2         4  
  2         141  
4             our $VERSION = "0.02";
5             $VERSION = eval $VERSION;
6             require Exporter;
7             our @ISA = qw(Exporter);
8             our @EXPORT_OK = qw(gbm_sample random_normal);
9 2     2   957 use Math::Random::Secure qw(rand);
  2         120331  
  2         630  
10              
11             =head1 NAME
12              
13             Math::Random::Normal::Leva - generate normally distributed PRN using Leva method
14              
15             =head1 VERSION
16              
17             This document describes Math::Random::Normal::Leva version 0.01
18              
19             =head1 SYNOPSIS
20              
21             use Math::Random::Normal::Leva;
22             my @normal = map { random_normal() } 1..1000;
23              
24             =head1 DESCRIPTION
25              
26             Generates normally distributed pseudorandom numbers using algorithm described
27             in the paper "A Fast Normal Random Number Generator", Joseph L. Leva, 1992
28             (L)
29              
30             =head1 FUNCTIONS
31              
32             =cut
33              
34             =head2 random_normal($rand)
35              
36             Returns a random number sampled from the normal distribution.
37              
38             =over 4
39              
40             =item I<$rand>
41              
42             is the value of the stock initially
43              
44             =cut
45              
46             # This algorithm comes from the paper
47             # "A Fast Normal Random Number Generator" (Leva, 1992)
48              
49             sub random_normal {
50 100000   50 100000 1 333655 my $rand = shift || \&rand;
51 100000         85459 my ( $s, $t ) = ( 0.449871, -0.386595 ); # Center point
52 100000         76531 my ( $a, $b ) = ( 0.19600, 0.25472 );
53              
54 100000         64945 my $nv;
55 100000         124513 while ( not defined $nv ) {
56 136528         175947 my ( $u, $v ) = ( $rand->(), 1.7156 * ( $rand->() - 0.5 ) );
57 136528         2303209 my $x = $u - $s;
58 136528         110224 my $y = abs($v) - $t;
59 136528         145611 my $Q = $x**2 + $y * ( $a * $y - $b * $x );
60 136528 100       185317 if ( $Q >= 0.27597 ) {
61 37129 100 100     92847 next if ( $Q > 0.27846 || $v**2 > -4 * $u**2 * log($u) );
62             }
63 100000         159086 $nv = $v / $u;
64             }
65              
66 100000         160463 return $nv;
67             }
68              
69             =head2 gbm_sample($price, $vol, $t, $r, $q, $rand)
70              
71             Generates a random sample price of a stock following Geometric Brownian Motion after t years.
72              
73             =over 4
74              
75             =item I<$price>
76              
77             is the value of the stock initially
78              
79             =item I<$vol>
80              
81             is the annual volatility of the stock
82              
83             =item I<$t>
84              
85             is the time elapsed in years
86              
87             =item I<$r>
88              
89             is the annualized drift rate
90              
91             =item I<$q>
92              
93             is the annualized dividend rate
94              
95             =item I<$rand>
96              
97             custom rand generated if not passed will use Math::Random::Secure::rand
98              
99             =back
100              
101             note: all rates are taken as decimals (.06 for 6%)
102              
103             =cut
104              
105             sub gbm_sample {
106 0     0 1   my ( $price, $vol, $time, $r, $q, $rand ) = @_;
107              
108 0           confess(
109             'All parameters are required to be set: generate_gbm($price, $annualized_vol, $time_in_years, $r_rate, $q_rate)'
110 0 0         ) if grep { not defined $_ } ( $price, $vol, $time, $r, $q );
111              
112 0           return $price *
113             exp( ( $r - $q - $vol * $vol / 2 ) * $time + $vol * sqrt($time) * random_normal($rand) );
114             }
115              
116             1;
117              
118             __END__