All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.timeandspace.smoothie.BinomialDistributionInverseCdfApproximation Maven / Gradle / Ivy

There is a newer version: 2.0.2
Show newest version
/* if Tracking hashCodeDistribution */
/*
 * Copyright (C) The SmoothieMap Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.timeandspace.smoothie;

import io.timeandspace.smoothie.Statistics.BinomialDistribution;
import io.timeandspace.smoothie.Statistics.NormalDistribution;

import static io.timeandspace.smoothie.PrecomputedBinomialCdfValues.MAX_SPLITS_WITH_PRECOMPUTED_CDF_VALUES;
import static io.timeandspace.smoothie.HashCodeDistribution.HASH_TABLE_HALF__SLOTS_MINUS_MAX_KEYS__SPLIT_CUMULATIVE_PROBS;

/**
 * Inverse CDF of binomial distribution ({@link BinomialDistribution#inverseCumulativeProbability})
 * is approximated using inverse CDF of normal distribution because the latter is much faster:
 * {@link BinomialDistribution#inverseCumulativeProbability} takes from 1500 to 5000 cycles
 * (depends statically on the arguments for BinomialDistribution; apparently depends on the speed of
 * convergence) while {@link NormalDistribution#inverseCumulativeProbability} takes about 500
 * cycles. {@link #normalApproximationCorrection} additionally takes only about 25 cycles. These
 * numbers are obtained on Intel Skylake.
 * TODO move the benchmark from smoothie-map-benchmarks to this project when it builds
 *
 * In the absolute worst case (the number of segments with skewed distribution of entries between
 * the halves is always on the edge of the reporting probability threshold
 * (maxProbabilityOfOccasionIfHashFunctionWasRandom), but doesn't cross it, so that {@link
 * HashCodeDistribution#hasReportedTooManySkewedSegmentSplits} is not set to
 * false and a SmoothieMap continues to track statistics and calculate probabilities) {@link
 * #inverseCumulativeProbability} might be called approximately 4 times for every 10 segment splits
 * on average (TODO run a test to check that empirically): about one in five segment splits is
 * skewed to the degree of having at least {@link
 * HashCodeDistribution#SKEWED_SEGMENT__HASH_TABLE_HALF__MAX_KEYS__MIN_ACCOUNTED} (29) keys in one
 * of the halves. (The "one in five" estimate is the inverse of the first probability in this table:
 * {@link HashCodeDistribution#HASH_TABLE_HALF__SLOTS_MINUS_MAX_KEYS__SPLIT_CUMULATIVE_PROBS}.)
 * Accordingly, for 11% of splits the probability should be checked two times (for two different
 * skewness levels independently, see the loop in {@link
 * HashCodeDistribution#doAccountSkewedSegmentSplit}), three times for 6% of splits and four times
 * for 3% of splits; this results in approximately 4 probability checks for every 10 segment splits
 * on average.
 *
 * The average occupancy of segments in a SmoothieMap always floats around 3/4 of the segment's max
 * capacity ({@link SmoothieMap#SEGMENT_MAX_ALLOC_CAPACITY}), i. e. 32 entries. The number of
 * segment splits is equal to the number of segments minus one in a SmoothieMap, so considering them
 * equal for this approximate calculation. It means that one {@link #inverseCumulativeProbability}
 * call is amortized among 32 * (10 / 4) = 80 insertions in a SmoothieMap. It means that the cost of
 * tracking and reporting skewed segment's hash table halves is about 500+ / 80 ~= 7 cycles per an
 * insertion. Note again that this is the absolute worst case of always having almost enough skewed
 * segments to exceed the reporting threshold; if there are less skewed segments, caching of
 * lastComputedMaxNonReportedSkewedSplits (see {@link
 * HashCodeDistribution#skewedSegment_splitStatsToCurrentAverageOrder}) allows to call {@link
 * #inverseCumulativeProbability} less than one time per four probability checks.
 *
 * So if {@link BinomialDistribution#inverseCumulativeProbability} itself was used the overhead of
 * reporting would be from 1500..5000 / 80 = 18..60 cycles per inserting in a SmoothieMap, that is
 * a prohibitively high cost.
 */
final class BinomialDistributionInverseCdfApproximation {

    /**
     * Returns max non-reported skewed segments for the given number of segment splits,
     * the specified probability of skewed segments as observed during splits, and the min required
     * confidence that an observed number of skewed segments is not occasional ("benign") and
     * therefore should be reported.
     *
     * Approximates {@code new BinomialDistribution(numSplits,
     *     HASH_TABLE_HALF__SLOTS_MINUS_MAX_KEYS__SPLIT_CUMULATIVE_PROBS[probIndex])
     *         .inverseCumulativeProbability(
     *             poorHashCodeDistribution_badOccasion_minRequiredConfidence)}.
     *
     * The semantics and the interface of this method are parallel to those of {@link
     * PrecomputedBinomialCdfValues#inverseCumulativeProbability}, but these methods must be called
     * on different ranges of numSplits: {@link PrecomputedBinomialCdfValues} when the number of
     * splits is less than or equal to {@link
     * PrecomputedBinomialCdfValues#MAX_SPLITS_WITH_PRECOMPUTED_CDF_VALUES}, {@link
     * BinomialDistributionInverseCdfApproximation} otherwise.
     *
     * @param probIndex index of probability value in {@link
     *        HashCodeDistribution#HASH_TABLE_HALF__SLOTS_MINUS_MAX_KEYS__SPLIT_CUMULATIVE_PROBS}.
     *        This is the probability of success for binomial distribution.
     * @param numSplits a number of segment split events in a {@link SmoothieMap} of some order at
     *        some stage of a SmoothieMap's life. See the comment for {@link
     *        HashCodeDistribution#numSegmentSplitsToCurrentAverageOrder} for explanations.
     *        This number is used as the argument (N) for binomial distribution.
     * @param poorHashCodeDistribution_badOccasion_minRequiredConfidence the argument for inverse
     *        CDF function, equals to `1.0 - maxProbabilityOfOccasionIfHashFunctionWasRandom`, as
     *        specified in {@link SmoothieMapBuilder#reportPoorHashCodeDistribution}
     * @return max non-reported skewed segments (inverse CDF result)
     */
    static int inverseCumulativeProbability(int probIndex, int numSplits,
            double poorHashCodeDistribution_badOccasion_minRequiredConfidence) {
        if (numSplits <= MAX_SPLITS_WITH_PRECOMPUTED_CDF_VALUES) {
            // PrecomputedBinomialCdfValues must be called instead, not only because it is able
            // to accept the numSplits, but also because BinomialDistributionInverseCdfApproximation
            // is increasingly imprecise the smaller numSplits:
            // https://en.wikipedia.org/wiki/Binomial_distribution#Normal_approximation says that
            // a good test for applicability of approximation of binomial distribution with normal
            // is numSplits > 9 * (1 - p) / p, that gives numSplits > 298 for the smallest
            // probability of success accepted by this method (0.02930494672052930127392
            // for probIndex = 3). But it's unknown whether the test should become even stricter
            // for approximation of inverse CDF of binomial distribution with inverse CDF of normal
            // distribution, so playing on the safe side here by allowing only numSplits greater
            // than MAX_SPLITS_WITH_PRECOMPUTED_CDF_VALUES (~1000).
            throw new AssertionError();
        }
        double p = HASH_TABLE_HALF__SLOTS_MINUS_MAX_KEYS__SPLIT_CUMULATIVE_PROBS[probIndex];
        double mean = ((double) numSplits) * p;
        double stdDev = mean * (1.0 - p);
        double normalApproximation = NormalDistribution.inverseCumulativeProbability(
                mean, stdDev, poorHashCodeDistribution_badOccasion_minRequiredConfidence);
        double poorHashCodeDistribution_benignOccasion_maxProbability =
                1.0 - poorHashCodeDistribution_badOccasion_minRequiredConfidence;
        double correction = normalApproximationCorrection(
                probIndex, poorHashCodeDistribution_benignOccasion_maxProbability);
        return Math.toIntExact(Math.round(normalApproximation + correction));
    }

    /**
     * A correction for normal approximation of inverse CDF of binomial distribution is needed
     * because the former is biased. Read the code and the comments in {@link
     * BinomialDistributionInverseCdfNormalApproximationBias} to gain better understanding of how
     * does this method work.
     */
    @SuppressWarnings({"UnnecessaryLocalVariable"})
    @VisibleForTesting
    static double normalApproximationCorrection(
            int probIndex, double poorHashCodeDistribution_benignOccasion_maxProbability) {
        float[] corrections = CORRECTIONS_PER_SKEW_PROB[probIndex];
        // The following logic in the inverse of the logic of [Exponential loop] in main() in
        // BinomialDistributionInverseCdfNormalApproximationBias.
        double maxProbability_fractionOfMax =
                poorHashCodeDistribution_benignOccasion_maxProbability /
                        SmoothieMap.POOR_HASH_CODE_DISTRIB__BENIGN_OCCASION__MAX_PROB__MAX;
        // lowerCorrectionIndex
        //   = Log[POOR_HASH_CODE_DISTRIB__BENIGN_OCCASION__MAX_PROB__EXP_BASE, maxProbability_fractionOfMax]
        //   = Log[maxProbability_fractionOfMax] / Log[POOR_HASH_CODE_DISTRIB__BENIGN_OCCASION__MAX_PROB__EXP_BASE]
        int lowerCorrectionIndex = (int) (
                Math.log(maxProbability_fractionOfMax)
                        / POOR_HASH_CODE_DISTRIB__BENIGN_OCCASION__MAX_PROB__EXP_BASE__LOG);
        int higherCorrectionIndex = lowerCorrectionIndex + 1;

        double lowerCorrection = (double) corrections[lowerCorrectionIndex];
        double higherCorrection = (double) corrections[higherCorrectionIndex];

        double higherProbability =
                SmoothieMap.POOR_HASH_CODE_DISTRIB__BENIGN_OCCASION__MAX_PROB__MAX *
                        Math.pow(POOR_HASH_CODE_DISTRIB__BENIGN_OCCASION__MAX_PROB__EXP_BASE,
                                (double) lowerCorrectionIndex);
        double lowerProbability;
        if (higherCorrectionIndex < corrections.length - 1) {
            lowerProbability = higherProbability *
                    POOR_HASH_CODE_DISTRIB__BENIGN_OCCASION__MAX_PROB__EXP_BASE;
        } else {
            lowerProbability =
                    SmoothieMap.POOR_HASH_CODE_DISTRIB__BENIGN_OCCASION__MAX_PROB__MIN;
        }

        if (poorHashCodeDistribution_benignOccasion_maxProbability < lowerProbability ||
                poorHashCodeDistribution_benignOccasion_maxProbability > higherProbability) {
            throw new AssertionError();
        }

        // Linear interpolation: "probabilities" are Xs, "corrections" are Ys. higherProbability and
        // lowerProbability are not actual values on the X axis, the actual values on the X
        // axis are `1 - xxxProbability`.
        double minusX0_plus1 = higherProbability;
        double minusX_plus1 = poorHashCodeDistribution_benignOccasion_maxProbability;
        double minusX1_plus1 = lowerProbability;

        double xMinusX0 = minusX0_plus1 - minusX_plus1;
        double x1MinusX0 = minusX0_plus1 - minusX1_plus1;

        double y0 = lowerCorrection;
        double y1 = higherCorrection;

        // Using approach (1) from this question: https://math.stackexchange.com/questions/907327.
        // Monotonicity and exactness-at-bounds concerns raised in that question are not important
        // here, because the precision of y0 and y1 (which are values from CORRECTIONS_PER_SKEW_PROB
        // array) is only 0.001 anyway: see a comment in
        // BinomialDistributionInverseCdfNormalApproximationBias.estimateMeanErrorAndSimpleRegression().
        double t = xMinusX0 / x1MinusX0;
        double y = y0 + ((y1 - y0) * t);

        double interpolatedCorrection = y;
        return interpolatedCorrection;
    }

    /**
     * Copied {@link
     * BinomialDistributionInverseCdfNormalApproximationBias#POOR_HASH_CODE_DISTRIB__BENIGN_OCCASION__MAX_PROB__EXP_BASE}.
     */
    private static final double POOR_HASH_CODE_DISTRIB__BENIGN_OCCASION__MAX_PROB__EXP_BASE =
            0.9255464154186664;

    private static final double POOR_HASH_CODE_DISTRIB__BENIGN_OCCASION__MAX_PROB__EXP_BASE__LOG =
            -0.07737099650418856;

    static {
        if (Math.log(POOR_HASH_CODE_DISTRIB__BENIGN_OCCASION__MAX_PROB__EXP_BASE) !=
                POOR_HASH_CODE_DISTRIB__BENIGN_OCCASION__MAX_PROB__EXP_BASE__LOG) {
            throw new AssertionError();
        }
    }

    /**
     * Each inner array corresponds to one probability of skewed segments (one of values from
     * {@link HashCodeDistribution#HASH_TABLE_HALF__SLOTS_MINUS_MAX_KEYS__SPLIT_CUMULATIVE_PROBS}),
     * "p" or "probabilityOfSuccess" in binomial distribution terms.
     *
     * Each inner array's value is a correction that should be applied to {@link
     * NormalDistribution#inverseCumulativeProbability} so that it approximates {@link
     * BinomialDistribution#inverseCumulativeProbability} without a bias for some specific argument.
     * Indexes in inner arrays translate to values of the arguments with an exponentiation rule: see
     * {@link
     * BinomialDistributionInverseCdfNormalApproximationBias#POOR_HASH_CODE_DISTRIB__BENIGN_OCCASION__MAX_PROB__EXP_BASE}
     * and {@link #normalApproximationCorrection} for more info.
     *
     * The precision of the bias corrections is about 0.001: see a comment in {@link
     * BinomialDistributionInverseCdfNormalApproximationBias#estimateMeanErrorAndSimpleRegression}.
     *
     * Computed in {@link BinomialDistributionInverseCdfNormalApproximationBias}, copied from
     * {@link io.timeandspace.smoothie.BinomialDistributionInverseCdfNormalApproximationBias.Output}.
     * See the comment for this class regarding the 10-digit precision of float values in inner
     * arrays.
     *
     * TODO in warmup procedure, access all values in all arrays to ensure they are mapped into
     *  memory
     */
    @SuppressWarnings("FloatingPointLiteralPrecision")
    private static final float[][] CORRECTIONS_PER_SKEW_PROB = {
            // Prob: 0.19341265286193732
            {-0.0293498039f, -0.0199182779f, -0.0106528075f, 0.0003727727f, 0.0107068541f,
                    0.0212952457f, 0.0325701572f, 0.0437135622f, 0.0543619283f, 0.0663404092f,
                    0.0777928978f, 0.0894301608f, 0.1006891504f, 0.1137766540f, 0.1253962368f,
                    0.1375181377f, 0.1498875022f, 0.1620640904f, 0.1747992486f, 0.1877894998f,
                    0.2006140351f, 0.2129683346f, 0.2264611423f, 0.2396189719f, 0.2518413961f,
                    0.2652647197f, 0.2784822285f, 0.2915766835f, 0.3049605489f, 0.3180832267f,
                    0.3317475319f, 0.3454345465f, 0.3587292433f, 0.3718332946f, 0.3857926726f,
                    0.3990947902f, 0.4127724171f, 0.4264045656f, 0.4396668971f, 0.4538764060f,
                    0.4678765535f, 0.4819669724f, 0.4955078661f, 0.5091878176f, 0.5237478614f,
                    0.5374088287f, 0.5512601137f, 0.5653114915f, 0.5801442266f, 0.5933577418f,
                    0.6078637838f, 0.6218159199f, 0.6361058354f, 0.6507502794f, 0.6645386815f,
                    0.6789593101f, 0.6930854321f, 0.7072513103f, 0.7214302421f, 0.7358757854f,
                    0.7500143051f, 0.7645889521f, 0.7787081599f, 0.7934131026f, 0.8078096509f,
                    0.8219586611f, 0.8362841606f, 0.8511216640f, 0.8653536439f, 0.8796117902f,
                    0.8942174911f, 0.9091762304f, 0.9234464765f, 0.9381239414f, 0.9527274966f,
                    0.9666527510f, 0.9811434150f, 0.9961093664f, 1.0100607872f, 1.0259015560f,
                    1.0394554138f, 1.0547440052f, 1.0697293282f, 1.0837690830f, 1.0987898111f,
                    1.1129040718f, 1.1279237270f, 1.1427096128f, 1.1572735310f, 1.1720954180f,
                    1.1868517399f, 1.2013897896f, 1.2170144320f, 1.2306869030f, 1.2460783720f,
                    1.2604910135f, 1.2755695581f, 1.2900885344f, 1.3047913313f, 1.3200113773f,
                    1.3343120813f, 1.3496599197f, 1.3644692898f, 1.3789991140f, 1.3941851854f,
                    1.4089064598f, 1.4238531590f, 1.4384306669f, 1.4538522959f, 1.4682853222f,
                    1.4832617044f, 1.4981952906f, 1.5129330158f, 1.5277873278f, 1.5427365303f,
                    1.5581328869f, 1.5730190277f, 1.5879575014f, 1.6028145552f, 1.6181076765f,
                    1.6329592466f, 1.6478259563f, 1.6620504856f, 1.6776720285f, 1.6929413080f,
                    1.7077519894f, 1.7226113081f, 1.7376224995f, 1.7524070740f},

            // Prob: 0.11140289106101875
            {-0.0379014313f, -0.0261197854f, -0.0130192898f, -0.0000673962f, 0.0134068942f,
                    0.0269587263f, 0.0409180820f, 0.0549202710f, 0.0691877976f, 0.0837387294f,
                    0.0982605219f, 0.1131160334f, 0.1284906864f, 0.1432594210f, 0.1588796228f,
                    0.1743642986f, 0.1904094964f, 0.2053262889f, 0.2216300368f, 0.2375045717f,
                    0.2538444996f, 0.2703366876f, 0.2864021957f, 0.3030304313f, 0.3196849823f,
                    0.3365378380f, 0.3525343835f, 0.3696685433f, 0.3861532509f, 0.4033874571f,
                    0.4205023944f, 0.4373828471f, 0.4545614421f, 0.4711523056f, 0.4888570309f,
                    0.5057988167f, 0.5232188702f, 0.5410544276f, 0.5576581955f, 0.5756082535f,
                    0.5932683349f, 0.6106078029f, 0.6281859875f, 0.6458594799f, 0.6635311842f,
                    0.6811907291f, 0.6987587810f, 0.7164686918f, 0.7345904708f, 0.7523578405f,
                    0.7699162364f, 0.7882824540f, 0.8057317138f, 0.8244326115f, 0.8419961333f,
                    0.8600861430f, 0.8780527115f, 0.8961583972f, 0.9143464565f, 0.9328238964f,
                    0.9507938623f, 0.9690241218f, 0.9872370362f, 1.0055892467f, 1.0229716301f,
                    1.0418566465f, 1.0597735643f, 1.0788867474f, 1.0964469910f, 1.1152989864f,
                    1.1329318285f, 1.1522475481f, 1.1699405909f, 1.1888303757f, 1.2068895102f,
                    1.2255815268f, 1.2440547943f, 1.2623819113f, 1.2811008692f, 1.2994682789f,
                    1.3179864883f, 1.3369151354f, 1.3552340269f, 1.3738572598f, 1.3925466537f,
                    1.4112933874f, 1.4296802282f, 1.4482580423f, 1.4671256542f, 1.4857743979f,
                    1.5041145086f, 1.5231261253f, 1.5421836376f, 1.5604972839f, 1.5792224407f,
                    1.5982604027f, 1.6168763638f, 1.6356155872f, 1.6539545059f, 1.6734272242f,
                    1.6918655634f, 1.7111874819f, 1.7296278477f, 1.7485281229f, 1.7670475245f,
                    1.7863335609f, 1.8049553633f, 1.8237490654f, 1.8425047398f, 1.8610275984f,
                    1.8805258274f, 1.8989101648f, 1.9185605049f, 1.9372274876f, 1.9557738304f,
                    1.9749890566f, 1.9939780235f, 2.0130231380f, 2.0315704346f, 2.0503461361f,
                    2.0694956779f, 2.0882911682f, 2.1076831818f, 2.1267554760f, 2.1462895870f,
                    2.1645300388f, 2.1837921143f, 2.2022449970f, 2.2217822075f},

            // Prob: 0.05946337525377032
            {-0.0427835360f, -0.0291024800f, -0.0148676159f, -0.0007729941f, 0.0149348695f,
                    0.0303475931f, 0.0460020080f, 0.0620034374f, 0.0784203187f, 0.0946559906f,
                    0.1116630360f, 0.1282888800f, 0.1454821527f, 0.1627380848f, 0.1804449409f,
                    0.1974658966f, 0.2152377218f, 0.2338209450f, 0.2509340644f, 0.2696189284f,
                    0.2879048884f, 0.3065820932f, 0.3250016272f, 0.3433329463f, 0.3622799218f,
                    0.3813498318f, 0.3989969492f, 0.4189024866f, 0.4378204048f, 0.4568325877f,
                    0.4758471251f, 0.4954762459f, 0.5149607062f, 0.5346294045f, 0.5536031723f,
                    0.5737468004f, 0.5932075977f, 0.6124647260f, 0.6328640580f, 0.6523823142f,
                    0.6727102399f, 0.6917463541f, 0.7114446759f, 0.7317919135f, 0.7520277500f,
                    0.7717351913f, 0.7919486165f, 0.8124851584f, 0.8320114613f, 0.8529548645f,
                    0.8734592795f, 0.8933904767f, 0.9134525657f, 0.9342185855f, 0.9540500045f,
                    0.9746896625f, 0.9951276779f, 1.0156608820f, 1.0366032124f, 1.0569708347f,
                    1.0776567459f, 1.0977989435f, 1.1185109615f, 1.1395140886f, 1.1602398157f,
                    1.1810902357f, 1.2013999224f, 1.2225233316f, 1.2427847385f, 1.2638908625f,
                    1.2845036983f, 1.3054964542f, 1.3262797594f, 1.3469794989f, 1.3683544397f,
                    1.3895046711f, 1.4104121923f, 1.4317548275f, 1.4522105455f, 1.4730441570f,
                    1.4935805798f, 1.5149184465f, 1.5363477468f, 1.5570597649f, 1.5783772469f,
                    1.5995383263f, 1.6205117702f, 1.6416691542f, 1.6628873348f, 1.6834287643f,
                    1.7053501606f, 1.7261861563f, 1.7475475073f, 1.7687762976f, 1.7896190882f,
                    1.8112030029f, 1.8324615955f, 1.8532754183f, 1.8749551773f, 1.8962292671f,
                    1.9174963236f, 1.9388232231f, 1.9602180719f, 1.9815039635f, 2.0025525093f,
                    2.0240356922f, 2.0457215309f, 2.0668418407f, 2.0884573460f, 2.1096544266f,
                    2.1312608719f, 2.1528117657f, 2.1735870838f, 2.1953878403f, 2.2171030045f,
                    2.2383842468f, 2.2590410709f, 2.2812907696f, 2.3025312424f, 2.3236744404f,
                    2.3458576202f, 2.3671686649f, 2.3886539936f, 2.4101204872f, 2.4319715500f,
                    2.4534490108f, 2.4748907089f, 2.4969248772f, 2.5183219910f},

            // Prob: 0.02930494672052930127392
            {-0.0462927930f, -0.0309282579f, -0.0157382768f, -0.0005130560f, 0.0160107948f,
                    0.0325537696f, 0.0492135435f, 0.0665163398f, 0.0838017538f, 0.1007185280f,
                    0.1188094169f, 0.1368042529f, 0.1550475508f, 0.1735061556f, 0.1920966953f,
                    0.2113856077f, 0.2300842255f, 0.2492610216f, 0.2684667408f, 0.2881497741f,
                    0.3073111475f, 0.3269310296f, 0.3467698395f, 0.3664225638f, 0.3864870965f,
                    0.4067004919f, 0.4270678163f, 0.4476672113f, 0.4675426781f, 0.4878982306f,
                    0.5086892843f, 0.5292266607f, 0.5497279167f, 0.5706669688f, 0.5911690593f,
                    0.6120008230f, 0.6333612204f, 0.6541322470f, 0.6759487987f, 0.6966789365f,
                    0.7181183696f, 0.7391004562f, 0.7598546147f, 0.7816494703f, 0.8026309609f,
                    0.8243218660f, 0.8459652066f, 0.8675382137f, 0.8893296719f, 0.9104934335f,
                    0.9320321679f, 0.9541980028f, 0.9760572314f, 0.9970070720f, 1.0189453363f,
                    1.0410242081f, 1.0626718998f, 1.0850458145f, 1.1068470478f, 1.1288017035f,
                    1.1501957178f, 1.1727114916f, 1.1949956417f, 1.2165093422f, 1.2390278578f,
                    1.2604625225f, 1.2825100422f, 1.3051807880f, 1.3274835348f, 1.3497557640f,
                    1.3717058897f, 1.3938970566f, 1.4161829948f, 1.4388599396f, 1.4607384205f,
                    1.4834687710f, 1.5058617592f, 1.5279083252f, 1.5505100489f, 1.5733710527f,
                    1.5950889587f, 1.6181439161f, 1.6402724981f, 1.6625990868f, 1.6855672598f,
                    1.7080913782f, 1.7302352190f, 1.7530299425f, 1.7749903202f, 1.7984309196f,
                    1.8206942081f, 1.8439601660f, 1.8660695553f, 1.8883332014f, 1.9114925861f,
                    1.9339004755f, 1.9563375711f, 1.9797099829f, 2.0019302368f, 2.0251233578f,
                    2.0468974113f, 2.0700869560f, 2.0928807259f, 2.1159744263f, 2.1386311054f,
                    2.1620137691f, 2.1840658188f, 2.2073173523f, 2.2302541733f, 2.2524335384f,
                    2.2762923241f, 2.2984127998f, 2.3209290504f, 2.3446996212f, 2.3668880463f,
                    2.3897564411f, 2.4129936695f, 2.4359345436f, 2.4590475559f, 2.4817214012f,
                    2.5041790009f, 2.5278310776f, 2.5511963367f, 2.5735521317f, 2.5963966846f,
                    2.6195063591f, 2.6425979137f, 2.6656162739f, 2.6885669231f}
    };

    private BinomialDistributionInverseCdfApproximation() {}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy