@Override
    public Estimate cumulativeProbability(double value, boolean inclusive)
    {
        // 1. compute the total probability for every existing range on the source
        // 2. find the range, r, where `value` falls
        // 3. compute the cumulative probability across all ranges that intersect [min, value]
        // 4. divide the result from (3) by the result from (1) to get the true cumulative
        //    probability of the disjoint domains over the original histogram
        if (Double.isNaN(value)) {
            return Estimate.unknown();
        }
        Optional<Range<Double>> optionalSpan = getSpan();
        if (!optionalSpan.isPresent()) {
            return Estimate.of(0.0);
        }
        Range<Double> span = optionalSpan.get();
        if (value <= span.lowerEndpoint()) {
            return Estimate.of(0.0);
        }
        Range<Double> input = Range.range(span.lowerEndpoint(), span.lowerBoundType(), value, inclusive ? BoundType.CLOSED : BoundType.OPEN);
        Estimate fullSetOverlap = calculateRangeSetOverlap(rangeSet.get());
        RangeSet<Double> spanned = rangeSet.get().subRangeSet(input);
        Estimate spannedOverlap = calculateRangeSetOverlap(spanned);

        return spannedOverlap.flatMap(spannedProbability ->
                fullSetOverlap.map(fullSetProbability -> {
                    if (fullSetProbability == 0.0) {
                        return 0.0;
                    }
                    return min(spannedProbability / fullSetProbability, 1.0);
                }));
    }
@Test
    public void testMultipleDisjunction()
    {
        StandardNormalHistogram source = new StandardNormalHistogram();
        RealDistribution dist = source.getDistribution();
        ConnectorHistogram constrained = disjunction(source, Range.closed(-2d, -1d));
        constrained = disjunction(constrained, Range.closed(1d, 2d));
        double rangeLeftProb = dist.cumulativeProbability(-1) - dist.cumulativeProbability(-2);
        double rangeRightProb = dist.cumulativeProbability(2) - dist.cumulativeProbability(1);
        double sumRangeProb = rangeLeftProb + rangeRightProb;
        assertEquals(constrained.cumulativeProbability(-2, true).getValue(), 0.0, 1E-8);
        assertEquals(constrained.cumulativeProbability(-1.5, true).getValue(), (dist.cumulativeProbability(-1.5d) - dist.cumulativeProbability(-2)) / sumRangeProb, 1E-8);
        assertEquals(constrained.cumulativeProbability(-1, true).getValue(), 0.5, 1E-8);
        assertEquals(constrained.cumulativeProbability(1, true).getValue(), 0.5, 1E-8);
        assertEquals(constrained.cumulativeProbability(1.5, true).getValue(), (rangeLeftProb / sumRangeProb) + ((dist.cumulativeProbability(1.5) - dist.cumulativeProbability(1.0)) / sumRangeProb));
        assertEquals(constrained.cumulativeProbability(2, true).getValue(), 1.0, 1E-8);
        assertEquals(constrained.cumulativeProbability(3, true).getValue(), 1.0, 1E-8);
    }