You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by ah...@apache.org on 2021/09/14 12:10:13 UTC
[commons-statistics] 08/08: Use a single instance of the standard
normal distribution
This is an automated email from the ASF dual-hosted git repository.
aherbert pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-statistics.git
commit 81cbacd3f43fb3ec2c188143fb641c36e22a3853
Author: aherbert <ah...@apache.org>
AuthorDate: Tue Sep 14 13:07:36 2021 +0100
Use a single instance of the standard normal distribution
The distribution is immutable. The underlying computations use static
methods and can be used across threads.
Note: A micro-optimisation to eliminate the mean=0 and SD=1 from the
computations used from NormalDistribution(0, 1) has not been performed
to aid maintenance. It is presumed that multiplication by 1 or addition
of 0 is insignificant compared to the calls to:
- Math.exp (density)
- Erf.value (cumulativeProbability)
- InverseErf.value (inverseCumulativeProbability)
Only the logDensity function would be expected to improve performance as
it would eliminate 1 subtraction and 1 devision to leave the computation
as 2 multiplications and a subtraction:
return -0.5 * x * x - halfLog2Pi
---
.../distribution/TruncatedNormalDistribution.java | 23 +++++++++++-----------
1 file changed, 12 insertions(+), 11 deletions(-)
diff --git a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/TruncatedNormalDistribution.java b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/TruncatedNormalDistribution.java
index 4f17d8b..08751ea 100644
--- a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/TruncatedNormalDistribution.java
+++ b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/TruncatedNormalDistribution.java
@@ -24,6 +24,10 @@ package org.apache.commons.statistics.distribution;
* Truncated normal distribution (Wikipedia)</a>
*/
public class TruncatedNormalDistribution extends AbstractContinuousDistribution {
+ /** A standard normal distribution used for calculations.
+ * This is immutable and thread-safe and can be used across instances. */
+ private static final NormalDistribution STANDARD_NORMAL = new NormalDistribution(0, 1);
+
/** Mean of parent normal distribution. */
private final double parentMean;
/** Standard deviation of parent normal distribution. */
@@ -37,8 +41,6 @@ public class TruncatedNormalDistribution extends AbstractContinuousDistribution
/** Upper bound of this distribution. */
private final double upper;
- /** A standard normal distribution used for calculations. */
- private final NormalDistribution standardNormal;
/** Stored value of @{code standardNormal.cumulativeProbability((lower - mean) / sd)} for faster computations. */
private final double cdfAlpha;
/**
@@ -75,21 +77,20 @@ public class TruncatedNormalDistribution extends AbstractContinuousDistribution
parentMean = mean;
parentSd = sd;
- standardNormal = new NormalDistribution(0, 1);
final double alpha = (lower - mean) / sd;
final double beta = (upper - mean) / sd;
- final double cdfBeta = standardNormal.cumulativeProbability(beta);
- cdfAlpha = standardNormal.cumulativeProbability(alpha);
+ final double cdfBeta = STANDARD_NORMAL.cumulativeProbability(beta);
+ cdfAlpha = STANDARD_NORMAL.cumulativeProbability(alpha);
cdfDelta = cdfBeta - cdfAlpha;
parentSdByCdfDelta = parentSd * cdfDelta;
logParentSdByCdfDelta = Math.log(parentSdByCdfDelta);
// Calculation of variance and mean.
- final double pdfAlpha = standardNormal.density(alpha);
- final double pdfBeta = standardNormal.density(beta);
+ final double pdfAlpha = STANDARD_NORMAL.density(alpha);
+ final double pdfBeta = STANDARD_NORMAL.density(beta);
final double pdfCdfDelta = (pdfAlpha - pdfBeta) / cdfDelta;
final double alphaBetaDelta = (alpha * pdfAlpha - beta * pdfBeta) / cdfDelta;
@@ -124,7 +125,7 @@ public class TruncatedNormalDistribution extends AbstractContinuousDistribution
if (x < lower || x > upper) {
return 0;
}
- return standardNormal.density((x - parentMean) / parentSd) / parentSdByCdfDelta;
+ return STANDARD_NORMAL.density((x - parentMean) / parentSd) / parentSdByCdfDelta;
}
/** {@inheritDoc} */
@@ -133,7 +134,7 @@ public class TruncatedNormalDistribution extends AbstractContinuousDistribution
if (x < lower || x > upper) {
return Double.NEGATIVE_INFINITY;
}
- return standardNormal.logDensity((x - parentMean) / parentSd) - logParentSdByCdfDelta;
+ return STANDARD_NORMAL.logDensity((x - parentMean) / parentSd) - logParentSdByCdfDelta;
}
/** {@inheritDoc} */
@@ -144,7 +145,7 @@ public class TruncatedNormalDistribution extends AbstractContinuousDistribution
} else if (x >= upper) {
return 1;
}
- return (standardNormal.cumulativeProbability((x - parentMean) / parentSd) - cdfAlpha) / cdfDelta;
+ return (STANDARD_NORMAL.cumulativeProbability((x - parentMean) / parentSd) - cdfAlpha) / cdfDelta;
}
/** {@inheritDoc} */
@@ -159,7 +160,7 @@ public class TruncatedNormalDistribution extends AbstractContinuousDistribution
} else if (p == 1) {
return upper;
}
- final double x = standardNormal.inverseCumulativeProbability(cdfAlpha + p * cdfDelta) * parentSd + parentMean;
+ final double x = STANDARD_NORMAL.inverseCumulativeProbability(cdfAlpha + p * cdfDelta) * parentSd + parentMean;
// Clip to support to handle floating-point error at the support bound
if (x <= lower) {
return lower;