1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.hipparchus.random;
23
24 import org.hipparchus.exception.LocalizedCoreFormats;
25 import org.hipparchus.exception.MathIllegalArgumentException;
26 import org.hipparchus.exception.NullArgumentException;
27 import org.hipparchus.util.FastMath;
28 import org.hipparchus.util.MathUtils;
29 import org.hipparchus.util.SinCos;
30
31
32
33
34
35
36
37
38
39
40 public class StableRandomGenerator implements NormalizedRandomGenerator {
41
42 private final RandomGenerator generator;
43
44
45 private final double alpha;
46
47
48 private final double beta;
49
50
51 private final double zeta;
52
53
54
55
56
57
58
59
60
61
62
63 public StableRandomGenerator(final RandomGenerator generator,
64 final double alpha, final double beta)
65 throws MathIllegalArgumentException, NullArgumentException {
66 if (generator == null) {
67 throw new NullArgumentException();
68 }
69
70 if (!(alpha > 0d && alpha <= 2d)) {
71 throw new MathIllegalArgumentException(LocalizedCoreFormats.OUT_OF_RANGE_LEFT,
72 alpha, 0, 2);
73 }
74
75 MathUtils.checkRangeInclusive(beta, -1, 1);
76
77 this.generator = generator;
78 this.alpha = alpha;
79 this.beta = beta;
80 if (alpha < 2d && beta != 0d) {
81 zeta = beta * FastMath.tan(FastMath.PI * alpha / 2);
82 } else {
83 zeta = 0d;
84 }
85 }
86
87
88
89
90
91
92 @Override
93 public double nextNormalizedDouble() {
94
95 double omega = -FastMath.log(generator.nextDouble());
96 double phi = FastMath.PI * (generator.nextDouble() - 0.5);
97
98
99 if (alpha == 2d) {
100 return FastMath.sqrt(2d * omega) * FastMath.sin(phi);
101 }
102
103 double x;
104
105
106 if (beta == 0d) {
107
108 if (alpha == 1d) {
109 x = FastMath.tan(phi);
110 } else {
111 x = FastMath.pow(omega * FastMath.cos((1 - alpha) * phi),
112 1d / alpha - 1d) *
113 FastMath.sin(alpha * phi) /
114 FastMath.pow(FastMath.cos(phi), 1d / alpha);
115 }
116 } else {
117
118 double cosPhi = FastMath.cos(phi);
119
120 if (FastMath.abs(alpha - 1d) > 1e-8) {
121 final SinCos scAlphaPhi = FastMath.sinCos(alpha * phi);
122 final SinCos scInvAlphaPhi = FastMath.sinCos(phi * (1.0 - alpha));
123 x = (scAlphaPhi.sin() + zeta * scAlphaPhi.cos()) / cosPhi *
124 (scInvAlphaPhi.cos() + zeta * scInvAlphaPhi.sin()) /
125 FastMath.pow(omega * cosPhi, (1 - alpha) / alpha);
126 } else {
127 double betaPhi = FastMath.PI / 2 + beta * phi;
128 x = 2d / FastMath.PI * (betaPhi * FastMath.tan(phi) - beta *
129 FastMath.log(FastMath.PI / 2d * omega * cosPhi / betaPhi));
130
131 if (alpha != 1d) {
132 x += beta * FastMath.tan(FastMath.PI * alpha / 2);
133 }
134 }
135 }
136 return x;
137 }
138 }