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 c3b0df4ea2bd4ebe9fd29e29c62bde5e77f365f5
Author: Alex Herbert <aherb...@apache.org>
AuthorDate: Fri Oct 8 23:34:12 2021 +0100

    STATISTICS-25: Correct use of the RegularizedBeta for T dist
    
    Detect when it is more accurate to compute using the complement and
    modify usage of the returned complementary p-value.
---
 .../statistics/distribution/TDistribution.java     | 27 ++++++++++++++++++----
 1 file changed, 23 insertions(+), 4 deletions(-)

diff --git 
a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/TDistribution.java
 
b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/TDistribution.java
index 25d0bcc..6f74322 100644
--- 
a/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/TDistribution.java
+++ 
b/commons-statistics-distribution/src/main/java/org/apache/commons/statistics/distribution/TDistribution.java
@@ -102,17 +102,36 @@ public class TDistribution extends 
AbstractContinuousDistribution {
         if (degreesOfFreedom > DOF_THRESHOLD_NORMAL) {
             return 0.5 * (1 + Erf.value(x * ONE_OVER_SQRT_TWO));
         }
-        final double a = 1 / (1 + x * x / degreesOfFreedom);
-        final double t = RegularizedBeta.value(a, dofOver2, 0.5);
+        final double x2overDf = x * x / degreesOfFreedom;
+        final double z = 1 / (1 + x2overDf);
+
+        // The RegularizedBeta has the complement:
+        //   I(z, a, b) = 1 - I(1 - z, a, b)
+        // This is used when z > (a + 1) / (2 + b + a).
+        // Detect this condition and directly use the complement.
+        if (z > (dofOver2 + 1) / (2.5 + dofOver2)) {
+            // zc = 1 - z; pc = 1 - p
+            final double zc = x2overDf / (1 + x2overDf);
+            final double pc = RegularizedBeta.value(zc, 0.5, dofOver2);
+
+            return x < 0 ?
+                // 0.5 * p == 0.5 * (1 - pc) = 0.5 - 0.5 * pc
+                0.5 - 0.5 * pc :
+                // 1 - 0.5 * p == 1 - 0.5 * (1 - pc) = 0.5 + 0.5 * pc
+                0.5 + 0.5 * pc;
+        }
+
+        final double p = RegularizedBeta.value(z, dofOver2, 0.5);
 
         return x < 0 ?
-            0.5 * t :
-            1 - 0.5 * t;
+            0.5 * p :
+            1 - 0.5 * p;
     }
 
     /** {@inheritDoc} */
     @Override
     public double survivalProbability(double x) {
+        // Exploit symmetry
         return cumulativeProbability(-x);
     }
 

Reply via email to