/src/quantlib/ql/math/randomnumbers/knuthuniformrng.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- mode: c++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
2 | | |
3 | | /* |
4 | | Copyright (C) 2000, 2001, 2002, 2003 RiskMap srl |
5 | | |
6 | | This file is part of QuantLib, a free-software/open-source library |
7 | | for financial quantitative analysts and developers - http://quantlib.org/ |
8 | | |
9 | | QuantLib is free software: you can redistribute it and/or modify it |
10 | | under the terms of the QuantLib license. You should have received a |
11 | | copy of the license along with this program; if not, please email |
12 | | <quantlib-dev@lists.sf.net>. The license is also available online at |
13 | | <https://www.quantlib.org/license.shtml>. |
14 | | |
15 | | This program is distributed in the hope that it will be useful, but WITHOUT |
16 | | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
17 | | FOR A PARTICULAR PURPOSE. See the license for more details. |
18 | | */ |
19 | | |
20 | | #include <ql/math/randomnumbers/knuthuniformrng.hpp> |
21 | | #include <ql/math/randomnumbers/seedgenerator.hpp> |
22 | | |
23 | | namespace QuantLib { |
24 | | |
25 | | const int KnuthUniformRng::KK = 100; |
26 | | const int KnuthUniformRng::LL = 37; |
27 | | const int KnuthUniformRng::TT = 70; |
28 | | const int KnuthUniformRng::QUALITY = 1009; |
29 | | |
30 | | KnuthUniformRng::KnuthUniformRng(long seed) |
31 | 0 | : ranf_arr_buf(QUALITY), ran_u(QUALITY) { |
32 | 0 | ranf_arr_ptr = ranf_arr_sentinel = ranf_arr_buf.size(); |
33 | 0 | ranf_start(seed != 0 ? seed : SeedGenerator::instance().get()); |
34 | 0 | } |
35 | | |
36 | 0 | void KnuthUniformRng::ranf_start(long seed) { |
37 | 0 | int t,s,j; |
38 | 0 | std::vector<double> u(KK+KK-1),ul(KK+KK-1); |
39 | 0 | double ulp=(1.0/(1L<<30))/(1L<<22); // 2 to the -52 |
40 | 0 | double ss=2.0*ulp*((seed&0x3fffffff)+2); |
41 | |
|
42 | 0 | for (j=0;j<KK;j++) { |
43 | 0 | u[j]=ss; ul[j]=0.0; // bootstrap the buffer |
44 | 0 | ss+=ss; if (ss>=1.0) ss-=1.0-2*ulp; // cyclic shift of 51 bits |
45 | 0 | } |
46 | 0 | for (;j<KK+KK-1;j++) u[j]=ul[j]=0.0; |
47 | 0 | u[1]+=ulp;ul[1]=ulp; // make u[1] (and only u[1]) "odd" |
48 | 0 | s=seed&0x3fffffff; |
49 | 0 | t=TT-1; |
50 | 0 | while (t != 0) { |
51 | 0 | for (j=KK-1;j>0;--j) ul[j+j]=ul[j],u[j+j]=u[j]; // "square" |
52 | 0 | for (j=KK+KK-2;j>KK-LL;j-=2) |
53 | 0 | ul[KK+KK-1-j]=0.0,u[KK+KK-1-j]=u[j]-ul[j]; |
54 | 0 | for (j=KK+KK-2;j>=KK;--j) |
55 | 0 | if (ul[j] != 0.0) { |
56 | 0 | ul[j - (KK - LL)] = ulp - ul[j - (KK - LL)], |
57 | 0 | u[j - (KK - LL)] = mod_sum(u[j - (KK - LL)], u[j]); |
58 | 0 | ul[j - KK] = ulp - ul[j - KK], u[j - KK] = mod_sum(u[j - KK], u[j]); |
59 | 0 | } |
60 | 0 | if (is_odd(s)) { // "multiply by z" |
61 | 0 | for (j=KK;j>0;--j) ul[j]=ul[j-1],u[j]=u[j-1]; |
62 | 0 | ul[0]=ul[KK],u[0]=u[KK]; // shift the buffer cyclically |
63 | 0 | if (ul[KK] != 0.0) |
64 | 0 | ul[LL] = ulp - ul[LL], u[LL] = mod_sum(u[LL], u[KK]); |
65 | 0 | } |
66 | 0 | if (s != 0) |
67 | 0 | s >>= 1; |
68 | 0 | else |
69 | 0 | t--; |
70 | 0 | } |
71 | 0 | for (j=0;j<LL;j++) ran_u[j+KK-LL]=u[j]; |
72 | 0 | for (;j<KK;j++) ran_u[j-LL]=u[j]; |
73 | 0 | } |
74 | | |
75 | | void KnuthUniformRng::ranf_array(std::vector<double>& aa, |
76 | 0 | int n) const { |
77 | 0 | int i,j; |
78 | 0 | for (j=0;j<KK;j++) aa[j]=ran_u[j]; |
79 | 0 | for (;j<n;j++) aa[j]=mod_sum(aa[j-KK],aa[j-LL]); |
80 | 0 | for (i=0;i<LL;i++,j++) ran_u[i]=mod_sum(aa[j-KK],aa[j-LL]); |
81 | 0 | for (;i<KK;i++,j++) ran_u[i]=mod_sum(aa[j-KK],ran_u[i-LL]); |
82 | 0 | } |
83 | | |
84 | 0 | double KnuthUniformRng::ranf_arr_cycle() const { |
85 | 0 | ranf_array(ranf_arr_buf,QUALITY); |
86 | 0 | ranf_arr_ptr = 1; |
87 | 0 | ranf_arr_sentinel = 100; |
88 | 0 | return ranf_arr_buf[0]; |
89 | 0 | } |
90 | | |
91 | | } |