Example #1
0
        /* namespace */
        public static String RawDoubleBitsToText(long pRawBits)
        {
            long rawBits    = pRawBits;
            bool isNegative = rawBits < 0; // sign bit is in the same place for long and double

            if (isNegative)
            {
                rawBits &= 0x7FFFFFFFFFFFFFFFL;
            }
            if (rawBits == 0)
            {
                return(isNegative ? "-0" : "0");
            }
            ExpandedDouble ed = new ExpandedDouble(rawBits);

            if (ed.GetBinaryExponent() < -1022)
            {
                // value is 'denormalised' which means it is less than 2^-1022
                // excel displays all these numbers as zero, even though calculations work OK
                return(isNegative ? "-0" : "0");
            }
            if (ed.GetBinaryExponent() == 1024)
            {
                // Special number NaN /InfInity
                // Normally one would not create HybridDecimal objects from these values
                // except in these cases Excel really tries to render them as if they were normal numbers
                if (rawBits == EXCEL_NAN_BITS)
                {
                    return("3.484840871308E+308");
                }
                // This is where excel really Gets it wrong
                // Special numbers like InfInity and NaN are interpreted according to
                // the standard rules below.
                isNegative = false; // except that the sign bit is ignored
            }
            NormalisedDecimal nd = ed.NormaliseBaseTen();
            StringBuilder     sb = new StringBuilder(MAX_TEXT_LEN + 1);

            if (isNegative)
            {
                sb.Append('-');
            }
            ConvertToText(sb, nd);
            return(sb.ToString());
        }
Example #2
0
        /**
         * This class attempts to reproduce Excel's behaviour for comparing numbers.  Results are
         * mostly the same as those from {@link Double#compare(double, double)} but with some
         * rounding.  For numbers that are very close, this code converts to a format having 15
         * decimal digits of precision and a decimal exponent, before completing the comparison.
         * <p/>
         * In Excel formula evaluation, expressions like "(0.06-0.01)=0.05" evaluate to "TRUE" even
         * though the equivalent java expression is <c>false</c>.  In examples like this,
         * Excel achieves the effect by having additional logic for comparison operations.
         * <p/>
         * <p/>
         * Note - Excel also gives special treatment to expressions like "0.06-0.01-0.05" which
         * evaluates to "0" (in java, rounding anomalies give a result of 6.9E-18).  The special
         * behaviour here is for different reasons to the example above:  If the last operator in a
         * cell formula is '+' or '-' and the result is less than 2<sup>50</sup> times smaller than
         * first operand, the result is rounded to zero.
         * Needless to say, the two rules are not consistent and it is relatively easy to find
         * examples that satisfy<br/>
         * "A=B" is "TRUE" but "A-B" is not "0"<br/>
         * and<br/>
         * "A=B" is "FALSE" but "A-B" is "0"<br/>
         * <br/>
         * This rule (for rounding the result of a final addition or subtraction), has not been
         * implemented in POI (as of Jul-2009).
         *
         * @return <code>negative, 0, or positive</code> according to the standard Excel comparison
         * of values <c>a</c> and <c>b</c>.
         */
        public static int Compare(double a, double b)
        {
            long rawBitsA = BitConverter.DoubleToInt64Bits(a);
            long rawBitsB = BitConverter.DoubleToInt64Bits(b);

            int biasedExponentA = IEEEDouble.GetBiasedExponent(rawBitsA);
            int biasedExponentB = IEEEDouble.GetBiasedExponent(rawBitsB);

            if (biasedExponentA == IEEEDouble.BIASED_EXPONENT_SPECIAL_VALUE)
            {
                throw new ArgumentException("Special double values are not allowed: " + ToHex(a));
            }
            if (biasedExponentB == IEEEDouble.BIASED_EXPONENT_SPECIAL_VALUE)
            {
                throw new ArgumentException("Special double values are not allowed: " + ToHex(a));
            }

            int cmp;

            // sign bit is in the same place for long and double:
            bool aIsNegative = rawBitsA < 0;
            bool bIsNegative = rawBitsB < 0;

            // compare signs
            if (aIsNegative != bIsNegative)
            {
                // Excel seems to have 'normal' comparison behaviour around zero (no rounding)
                // even -0.0 < +0.0 (which is not quite the initial conclusion of bug 47198)
                return(aIsNegative ? -1 : +1);
            }

            // then compare magnitudes (IEEE 754 has exponent bias specifically to allow this)
            cmp = biasedExponentA - biasedExponentB;
            int absExpDiff = Math.Abs(cmp);

            if (absExpDiff > 1)
            {
                return(aIsNegative ? -cmp : cmp);
            }

            if (absExpDiff == 1)
            {
                // special case exponent differs by 1.  There is still a chance that with rounding the two quantities could end up the same
            }
            else
            {
                // else - sign and exponents equal
                if (rawBitsA == rawBitsB)
                {
                    // fully equal - exit here
                    return(0);
                }
            }
            if (biasedExponentA == 0)
            {
                if (biasedExponentB == 0)
                {
                    return(CompareSubnormalNumbers(rawBitsA & IEEEDouble.FRAC_MASK, rawBitsB & IEEEDouble.FRAC_MASK, aIsNegative));
                }
                // else biasedExponentB is 1
                return(-CompareAcrossSubnormalThreshold(rawBitsB, rawBitsA, aIsNegative));
            }
            if (biasedExponentB == 0)
            {
                // else biasedExponentA is 1
                return(+CompareAcrossSubnormalThreshold(rawBitsA, rawBitsB, aIsNegative));
            }

            // sign and exponents same, but fractional bits are different

            ExpandedDouble    edA = ExpandedDouble.FromRawBitsAndExponent(rawBitsA, biasedExponentA - IEEEDouble.EXPONENT_BIAS);
            ExpandedDouble    edB = ExpandedDouble.FromRawBitsAndExponent(rawBitsB, biasedExponentB - IEEEDouble.EXPONENT_BIAS);
            NormalisedDecimal ndA = edA.NormaliseBaseTen().RoundUnits();
            NormalisedDecimal ndB = edB.NormaliseBaseTen().RoundUnits();

            cmp = ndA.CompareNormalised(ndB);
            if (aIsNegative)
            {
                return(-cmp);
            }
            return(cmp);
        }