/// <summary>
        /// Computes the specified quantile elements over the values previously added.
        /// </summary>
        /// <param name="phis">the quantiles for which elements are to be computed. Each phi must be in the interval (0.0,1.0]. <tt>phis</tt> must be sorted ascending.</param>
        /// <returns>the approximate quantile elements.</returns>
        public override DoubleArrayList QuantileElements(DoubleArrayList phis)
        {
            if (precomputeEpsilon <= 0.0)
            {
                return(base.QuantileElements(phis));
            }

            int quantilesToPrecompute = (int)Utils.EpsilonCeiling(1.0 / precomputeEpsilon);

            /*
             * if (phis.Count > quantilesToPrecompute) {
             *  // illegal use case!
             *  // we compute results, but loose explicit approximation guarantees.
             *  return base.QuantileElements(phis);
             * }
             */

            //select that quantile from the precomputed set that corresponds to a position closest to phi.
            phis = phis.Copy();
            double e = precomputeEpsilon;

            for (int index = phis.Size; --index >= 0;)
            {
                double phi = phis[index];
                int    i   = (int)System.Math.Round(((2.0 * phi / e) - 1.0) / 2.0); // finds closest
                i = System.Math.Min(quantilesToPrecompute - 1, System.Math.Max(0, i));
                double augmentedPhi = (e / 2.0) * (1 + 2 * i);
                phis[index] = augmentedPhi;
            }

            return(base.QuantileElements(phis));
        }
        /// <summary>
        /// Computes the specified quantile elements over the values previously added.
        /// </summary>
        /// <param name="phis">the quantiles for which elements are to be computed. Each phi must be in the interval [0.0,1.0]. <tt>phis</tt> must be sorted ascending.</param>
        /// <returns>the approximate quantile elements.</returns>
        public virtual DoubleArrayList QuantileElements(DoubleArrayList phis)
        {
            /*
             * //check parameter
             */
            List <Double> sortedPhiList = phis.Copy().ToList();

            sortedPhiList.Sort();
            if (!phis.Equals(sortedPhiList))
            {
                throw new ArgumentException(Cern.LocalizedResources.Instance().Exception_PhisMustBeAscending);
            }

            //System.out.println("starting to augment missing values, if necessary...");

            phis = PreProcessPhis(phis);

            long[] triggerPositions = new long[phis.Size];
            long   totalSize        = this.bufferSet.TotalSize;

            for (int i = phis.Size; --i >= 0;)
            {
                triggerPositions[i] = Utils.EpsilonCeiling(phis[i] * totalSize) - 1;
            }

            //System.out.println("triggerPositions="+cern.colt.Arrays.ToString(triggerPositions));
            //System.out.println("starting to determine quantiles...");
            //System.out.println(bufferSet);

            DoubleBuffer[] fullBuffers      = bufferSet.GetFullOrPartialBuffers();
            double[]       quantileElements = new double[phis.Size];

            //do the main work: determine values at given positions in sorted sequence
            return(new DoubleArrayList(bufferSet.GetValuesAtPositions(fullBuffers, triggerPositions)));
        }
 protected new DoubleArrayList PreProcessPhis(DoubleArrayList phis)
 {
     if (beta > 1.0)
     {
         phis = phis.Copy();
         for (int i = phis.Size; --i >= 0;)
         {
             phis[i] = (2 * phis[i] + beta - 1) / (2 * beta);
         }
     }
     return(phis);
 }