What's wrong
IDistribution.SurvivalFunction defaults to 1.0 - Cdf(value) (Essentials/IDistribution.cs L72). Its remarks say that a distribution with a directly computable tail should declare this member. Exponential, Geometric, LogNormal, Normal and Poisson do. Triangular, Uniform, Bernoulli and Categorical do not, although each has a closed-form tail, so they lose precision the same way #50 describes for Binomial.
Reproduction (net10.0, current main)
| Call |
Actual |
Exact |
Triangular(0, 0, 1).SurvivalFunction(0.999999999) |
0 |
1e-18 |
Triangular(0, 0, 1).SurvivalFunction(0.9999999) |
9.992e-15 |
1e-14 |
Uniform(-1, 1).SurvivalFunction(0.9999999999999999) |
0 |
5.55e-17 |
Bernoulli(1e-20).SurvivalFunction(0) |
0 |
1e-20 |
Bernoulli(0.1).SurvivalFunction(0) |
0.09999999999999998 |
0.1 |
Categorical([1, 1e-20]).SurvivalFunction(0) |
0 |
1e-20 |
Callers that use the survival function for rare-event probabilities, p-values or log-likelihoods get 0, and then -Infinity after a log, where the true value is small but representable.
Suggested fix
Declare SurvivalFunction on each provider:
- Triangular: for
v ≥ mode, return (max − v)² / ((max − min)(max − mode)). Below the mode, 1 − Cdf is well conditioned.
- Uniform: return
(max − v) / (max − min), clamped to [0, 1].
- Bernoulli: return
v < 0 ? 1 : v < 1 ? p : 0.
- Categorical: precompute upper cumulative sums, adding from the last category down, and index into them.
Add rows like the table above to the distribution tests.
This is related to #50 (Binomial), but it covers different providers and needs a different fix.
What's wrong
IDistribution.SurvivalFunctiondefaults to1.0 - Cdf(value)(Essentials/IDistribution.csL72). Its remarks say that a distribution with a directly computable tail should declare this member. Exponential, Geometric, LogNormal, Normal and Poisson do. Triangular, Uniform, Bernoulli and Categorical do not, although each has a closed-form tail, so they lose precision the same way #50 describes for Binomial.Reproduction (net10.0, current
main)Triangular(0, 0, 1).SurvivalFunction(0.999999999)01e-18Triangular(0, 0, 1).SurvivalFunction(0.9999999)9.992e-151e-14Uniform(-1, 1).SurvivalFunction(0.9999999999999999)05.55e-17Bernoulli(1e-20).SurvivalFunction(0)01e-20Bernoulli(0.1).SurvivalFunction(0)0.099999999999999980.1Categorical([1, 1e-20]).SurvivalFunction(0)01e-20Callers that use the survival function for rare-event probabilities, p-values or log-likelihoods get
0, and then-Infinityafter a log, where the true value is small but representable.Suggested fix
Declare
SurvivalFunctionon each provider:v ≥ mode, return(max − v)² / ((max − min)(max − mode)). Below the mode,1 − Cdfis well conditioned.(max − v) / (max − min), clamped to [0, 1].v < 0 ? 1 : v < 1 ? p : 0.Add rows like the table above to the distribution tests.
This is related to #50 (Binomial), but it covers different providers and needs a different fix.