View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.rng.sampling.distribution;
18  
19  import org.apache.commons.rng.UniformRandomProvider;
20  
21  /**
22   * <a href="https://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform">
23   * Box-Muller algorithm</a> for sampling from a Gaussian distribution.
24   *
25   * <p>Sampling uses:</p>
26   *
27   * <ul>
28   *   <li>{@link UniformRandomProvider#nextDouble()}
29   *   <li>{@link UniformRandomProvider#nextLong()}
30   * </ul>
31   *
32   * @since 1.0
33   *
34   * @deprecated Since version 1.1. Please use {@link BoxMullerNormalizedGaussianSampler}
35   * and {@link GaussianSampler} instead.
36   */
37  @Deprecated
38  public class BoxMullerGaussianSampler
39      extends SamplerBase
40      implements ContinuousSampler {
41      /** Next gaussian. */
42      private double nextGaussian = Double.NaN;
43      /** Mean. */
44      private final double mean;
45      /** standardDeviation. */
46      private final double standardDeviation;
47      /** Underlying source of randomness. */
48      private final UniformRandomProvider rng;
49  
50      /**
51       * Create an instance.
52       *
53       * @param rng Generator of uniformly distributed random numbers.
54       * @param mean Mean of the Gaussian distribution.
55       * @param standardDeviation Standard deviation of the Gaussian distribution.
56       * @throws IllegalArgumentException if {@code standardDeviation <= 0}
57       */
58      public BoxMullerGaussianSampler(UniformRandomProvider rng,
59                                      double mean,
60                                      double standardDeviation) {
61          this(mean, InternalUtils.requireStrictlyPositiveFinite(standardDeviation, "standardDeviation"), rng);
62      }
63  
64      /**
65       * @param rng Generator of uniformly distributed random numbers.
66       * @param mean Mean of the Gaussian distribution.
67       * @param standardDeviation Standard deviation of the Gaussian distribution.
68       */
69      private BoxMullerGaussianSampler(double mean,
70                                       double standardDeviation,
71                                       UniformRandomProvider rng) {
72          super(null);
73          this.rng = rng;
74          this.mean = mean;
75          this.standardDeviation = standardDeviation;
76      }
77  
78      /** {@inheritDoc} */
79      @Override
80      public double sample() {
81          final double random;
82          if (Double.isNaN(nextGaussian)) {
83              // Generate a pair of Gaussian numbers.
84  
85              // Avoid zero for the uniform deviate y.
86              // The extreme tail of the sample is:
87              // y = 2^-53
88              // r = 8.57167
89              final double x = rng.nextDouble();
90              final double y = InternalUtils.makeNonZeroDouble(rng.nextLong());
91              final double alpha = 2 * Math.PI * x;
92              final double r = Math.sqrt(-2 * Math.log(y));
93  
94              // Return the first element of the generated pair.
95              random = r * Math.cos(alpha);
96  
97              // Keep second element of the pair for next invocation.
98              nextGaussian = r * Math.sin(alpha);
99          } else {
100             // Use the second element of the pair (generated at the
101             // previous invocation).
102             random = nextGaussian;
103 
104             // Both elements of the pair have been used.
105             nextGaussian = Double.NaN;
106         }
107 
108         return standardDeviation * random + mean;
109     }
110 
111     /** {@inheritDoc} */
112     @Override
113     public String toString() {
114         return "Box-Muller Gaussian deviate [" + rng.toString() + "]";
115     }
116 }