Example #1
0
        /// <summary>
        /// Finds the bins for Single values (and integer labels)
        /// </summary>
        /// <param name="maxBins">Maximum number of bins</param>
        /// <param name="minBinSize">Minimum number of values per bin (stopping condition for greedy bin splitting)</param>
        /// <param name="nLabels">Cardinality of the labels</param>
        /// <param name="values">The feature values</param>
        /// <param name="labels">The corresponding label values</param>
        /// <returns>An array of split points, no more than <paramref name="maxBins"/> total (but maybe less), ending with PositiveInfinity</returns>
        public Single[] FindBins(int maxBins, int minBinSize, int nLabels, IList <Single> values, IList <int> labels)
        {
            // prepare the values: count distinct values and populate the value pair array
            _valueCount       = values.Count;
            _labelCardinality = nLabels;
            _maxBins          = maxBins;
            _minBinSize       = minBinSize;
            Contracts.Assert(_valueCount == labels.Count);
            _distinctValueCount = 0;
            var seenValues = new HashSet <Single>();
            var valuePairs = new ValuePair <Single> [_valueCount];

            for (int i = 0; i < _valueCount; i++)
            {
                valuePairs[i] = new ValuePair <Single>(values[i], labels[i]);
                if (seenValues.Add(values[i]))
                {
                    _distinctValueCount++;
                }
            }
            Array.Sort(valuePairs);

            // populate the cumulative counts with unique values
            _cumulativeCounts = new int[_distinctValueCount, _labelCardinality + 1];
            var    distinctValues = new Single[_distinctValueCount];
            Single curValue       = Single.NegativeInfinity;
            int    curIndex       = -1;

            foreach (var pair in valuePairs)
            {
                Contracts.Assert(pair.Value >= curValue);
                if (pair.Value > curValue || curIndex < 0)
                {
                    curValue = pair.Value;
                    curIndex++;
                    distinctValues[curIndex] = curValue;
                    if (curIndex > 0)
                    {
                        for (int i = 0; i < _labelCardinality + 1; i++)
                        {
                            _cumulativeCounts[curIndex, i] = _cumulativeCounts[curIndex - 1, i];
                        }
                    }
                }
                _cumulativeCounts[curIndex, pair.Label]++;
                _cumulativeCounts[curIndex, _labelCardinality]++;
            }

            Contracts.Assert(curIndex == _distinctValueCount - 1);

            var boundaries = FindBinsCore();

            Contracts.Assert(Utils.Size(boundaries) > 0);
            Contracts.Assert(boundaries.Length == 1 && boundaries[0] == 0 || boundaries[0] > 0, "boundaries are exclusive, can't have 0");
            Contracts.Assert(boundaries[boundaries.Length - 1] == _distinctValueCount);

            // transform boundary indices back into bin upper bounds
            var numUpperBounds = boundaries.Length;

            Single[] result = new Single[numUpperBounds];
            for (int i = 0; i < numUpperBounds - 1; i++)
            {
                var split = boundaries[i];
                result[i] = BinFinderBase.GetSplitValue(distinctValues[split - 1], distinctValues[split]);

                // Even though distinctValues may contain infinities, the boundaries may not be infinite:
                // GetSplitValue(a,b) only returns +-inf if a==b==+-inf,
                // and distinctValues won't contain more than one +inf or -inf.
                Contracts.Assert(FloatUtils.IsFinite(result[i]));
            }

            result[numUpperBounds - 1] = Single.PositiveInfinity;
            AssertStrictlyIncreasing(result);

            return(result);
        }
        public static bool TryParse(ReadOnlySpan <char> span, out Single value, out int ichEnd)
        {
            bool  neg = false;
            ulong num = 0;
            long  exp = 0;

            ichEnd = 0;
            if (!TryParseCore(span, ref ichEnd, ref neg, ref num, ref exp))
            {
                return(TryParseSpecial(span, ref ichEnd, out value));
            }

            if (num == 0)
            {
                value = 0;
                goto LDone;
            }

            // The Single version simply looks up the power of 10 in a table (as a Double), casts num
            // to Double, multiples, then casts to Single.
            Double res;

            if (exp >= 0)
            {
                if (exp == 0)
                {
                    res = 1;
                }
                else if (exp > _mpe10Dbl.Length)
                {
                    value = Single.PositiveInfinity;
                    goto LDone;
                }
                else
                {
                    res = _mpe10Dbl[(int)exp - 1];
                }
            }
            else
            {
                if (-exp > _mpne10Dbl.Length)
                {
                    value = 0;
                    goto LDone;
                }
                res = _mpne10Dbl[-(int)exp - 1];
            }

            // REVIEW: casting ulong to Double doesn't always get the answer correct.
            // Casting a non-negative long does work, though, so we jump through hoops to make
            // sure the top bit is clear and cast to long before casting to Double.
            Double tmp;

            if ((long)num >= 0)
            {
                tmp = (Double)(long)num;
            }
            else
            {
                tmp  = (Double)(long)((num >> 1) | (num & 1));
                tmp += tmp;
            }

            res  *= tmp;
            value = (Single)res;

LDone:
            if (neg)
            {
                value = -value;
            }

#if COMPARE_BCL
            if (!_failed)
            {
                string str = span.ToString();
                Single x;
                if (!Single.TryParse(str, out x))
                {
                    // Single.TryParse doesn't gracefully handle overflow to infinity.
                    if (!Single.IsPositiveInfinity(value) && !Single.IsNegativeInfinity(value))
                    {
                        _failed = true;
                        Contracts.Assert(false, string.Format("Single.TryParse failed on: {0}", str));
                    }
                }
                else if (FloatUtils.GetBits(x) != FloatUtils.GetBits(value))
                {
                    // Double.TryParse gets negative zero wrong!
                    if (FloatUtils.GetBits(x) != 0 || FloatUtils.GetBits(value) != 0x80000000U || !neg)
                    {
                        _failed = true;
                        Contracts.Assert(false, string.Format("FloatParser disagrees with Single.TryParse on: {0} ({1} vs {2})", str, FloatUtils.GetBits(x), FloatUtils.GetBits(value)));
                    }
                }
            }
#endif

            return(true);
        }
        public static bool TryParse(ReadOnlySpan <char> span, out Double value, out int ichEnd)
        {
            bool  neg = false;
            ulong num = 0;
            long  exp = 0;

            ichEnd = 0;
            if (!TryParseCore(span, ref ichEnd, ref neg, ref num, ref exp))
            {
                return(TryParseSpecial(span, ref ichEnd, out value));
            }

            if (num == 0)
            {
                value = 0;
                goto LDone;
            }

            ulong mul;
            int   e2;

            if (exp >= 0)
            {
                if (exp == 0)
                {
                    // REVIEW: casting ulong to Double doesn't always get the answer correct.
                    // Casting a non-negative long does work, though, so we jump through hoops to make
                    // sure the top bit is clear and cast to long before casting to Double.
                    if ((long)num >= 0)
                    {
                        value = (Double)(long)num;
                    }
                    else
                    {
                        value  = (Double)(long)((num >> 1) | (num & 1));
                        value += value;
                    }
                    goto LDone;
                }
                if (exp <= 22 && num < (1UL << 53))
                {
                    // Can just use Double division, since both 10^|exp| and num can be exactly represented in Double.
                    // REVIEW: there are potential other "easy" cases, like when num isn't less than 2^54, but
                    // it ends with enough zeros that it can be made so by shifting.
                    Contracts.Assert((long)(Double)(long)num == (long)num);
                    value = (Double)(long)num * _mpe10Dbl[exp - 1];
                    goto LDone;
                }
                if (exp > _mpe10Man.Length)
                {
                    value = Double.PositiveInfinity;
                    goto LDone;
                }
                int index = (int)exp - 1;
                mul = _mpe10Man[index];
                e2  = _mpe10e2[index];
            }
            else
            {
                if (-exp <= 22 && num < (1UL << 53))
                {
                    // Can just use Double division, since both 10^|exp| and num can be exactly represented in Double.
                    // REVIEW: there are potential other "easy" cases, like when num isn't less than 2^54, but
                    // it ends with enough zeros that it can be made so by shifting.
                    Contracts.Assert((long)(Double)(long)num == (long)num);
                    value = (Double)(long)num / _mpe10Dbl[-exp - 1];
                    goto LDone;
                }
                if (-exp > _mpne10Man.Length)
                {
                    value = 0;
                    goto LDone;
                }
                int index = -(int)exp - 1;
                mul = _mpne10Man[index];
                e2  = -_mpne10ne2[index];
            }

            // Normalize the mantissa and initialize the base-2 (biased) exponent.
            // Ensure that the high bit is set.
            if ((num & 0xFFFFFFFF00000000UL) == 0)
            {
                num <<= 32; e2 -= 32;
            }
            if ((num & 0xFFFF000000000000UL) == 0)
            {
                num <<= 16; e2 -= 16;
            }
            if ((num & 0xFF00000000000000UL) == 0)
            {
                num <<= 8; e2 -= 8;
            }
            if ((num & 0xF000000000000000UL) == 0)
            {
                num <<= 4; e2 -= 4;
            }
            if ((num & 0xC000000000000000UL) == 0)
            {
                num <<= 2; e2 -= 2;
            }

            // Don't force the top bit to be non-zero, since we'll just have to clear it later....
            // if ((num & 0x8000000000000000UL) == 0) { num <<= 1; e2 -= 1; }

            // The high bit of mul is 1, and at least one of the top two bits of num is non-zero.
            // Taking the high 64 bits of the 128 bit result should give us enough bits to get the
            // right answer most of the time. Note, that it's not guaranteed that we always get the
            // right answer. Guaranteeing that takes much more work.... See the paper by David Gay at
            // https://www.ampl.com/REFS/rounding.pdf.
            Contracts.Assert((num & TopTwoBits) != 0);
            Contracts.Assert((mul & TopBit) != 0);

            // Multiply mul into num, keeping the high ulong.
            // REVIEW: Can this be made faster? It would be nice to use the _umul128 intrinsic.
            ulong hi1 = mul >> 32;
            ulong lo1 = mul & 0xFFFFFFFFUL;
            ulong hi2 = num >> 32;
            ulong lo2 = num & 0xFFFFFFFFUL;

            num   = hi1 * hi2;
            hi1  *= lo2;
            hi2  *= lo1;
            num  += hi1 >> 32;
            num  += hi2 >> 32;
            hi1 <<= 32;
            hi2 <<= 32;
            if ((hi1 += hi2) < hi2)
            {
                num++;
            }
            lo1 *= lo2;
            if ((lo1 += hi1) < hi1)
            {
                num++;
            }

            // Cast to long first since ulong => Double is broken.
            Contracts.Assert((num & TopThreeBits) != 0);
            if ((long)num >= 0)
            {
                // Capture a non-zero lo to avoid an artificial tie.
                if (lo1 != 0)
                {
                    num |= 1;
                }
                value = (Double)(long)num;
            }
            else
            {
                if ((lo1 | (num & 1)) != 0)
                {
                    num |= 2;
                }
                value = (Double)(long)(num >> 1);
                e2++;
            }

            // Adjust the base-2 exponent.
            e2 += 0x3FF;
            if (e2 >= 0x7FF)
            {
                Contracts.Assert(exp > 0);
                value = Double.PositiveInfinity;
                goto LDone;
            }
            if (e2 <= 0)
            {
                // Break the exponent adjustment into two operations.
                Contracts.Assert(exp < 0);
                mul = 1UL << 52;
                unsafe { value *= *(Double *)&mul; }
                e2 += 0x3FF - 1;
                Contracts.Assert(e2 > 0);
            }

            // Multiply by the exponent adjustment.
            Contracts.Assert(0 < e2 & e2 < 0x7FF);
            mul = (ulong)e2 << 52;
            unsafe { value *= *(Double *)&mul; }

LDone:
            if (neg)
            {
                value = -value;
            }

#if COMPARE_BCL
            string str = span.ToString();
            Double x;
            if (!Double.TryParse(str, out x))
            {
                // Double.TryParse doesn't gracefully handle overflow to infinity.
                if (!Double.IsPositiveInfinity(value) && !Double.IsNegativeInfinity(value))
                {
                    if (!_failed)
                    {
                        _failed = true;
                        Contracts.Assert(false, string.Format("Double.TryParse failed on: {0}", str));
                    }
                }
            }
            else if (FloatUtils.GetBits(x) != FloatUtils.GetBits(value))
            {
                // Double.TryParse gets negative zero wrong!
                if (FloatUtils.GetBits(x) != 0 || FloatUtils.GetBits(value) != TopBit || !neg)
                {
                    System.Diagnostics.Debug.WriteLine("*** FloatParser disagrees with Double.TryParse on: {0} ({1} vs {2})", str, FloatUtils.GetBits(x), FloatUtils.GetBits(value));
                }
            }
#endif

            return(true);
        }
Example #4
0
 private static float PowerOfTwo(int exp)
 {
     Contracts.Assert(0 <= exp && exp < ExpInf);
     return(FloatUtils.GetPowerOfTwoSingle(exp));
 }