Beispiel #1
0
        static int d2s_buffered_n(double f, Span <char> result)
        {
            // Step 1: Decode the floating-point number, and unify normalized and subnormal cases.
            ulong bits = double_to_bits(f);

            // Decode bits into sign, mantissa, and exponent.
            bool  ieeeSign     = ((bits >> (DOUBLE_MANTISSA_BITS + DOUBLE_EXPONENT_BITS)) & 1) != 0;
            ulong ieeeMantissa = bits & ((1ul << DOUBLE_MANTISSA_BITS) - 1);
            uint  ieeeExponent = (uint)((bits >> DOUBLE_MANTISSA_BITS) & ((1u << DOUBLE_EXPONENT_BITS) - 1));

            // Case distinction; exit early for the easy cases.
            if (ieeeExponent == ((1u << DOUBLE_EXPONENT_BITS) - 1u) || (ieeeExponent == 0 && ieeeMantissa == 0))
            {
                return(copy_special_str(result, ieeeSign, Convert.ToBoolean(ieeeExponent), Convert.ToBoolean(ieeeMantissa)));
            }

            floating_decimal_64 v = default(floating_decimal_64);
            bool isSmallInt       = d2d_small_int(ieeeMantissa, ieeeExponent, ref v);

            if (isSmallInt)
            {
                // For small integers in the range [1, 2^53), v.mantissa might contain trailing (decimal) zeros.
                // For scientific notation we need to move these zeros into the exponent.
                // (This is not needed for fixed-point notation, so it might be beneficial to trim
                // trailing zeros in to_chars only if needed - once fixed-point notation output is implemented.)
                for (; ;)
                {
                    ulong q = div10(v.mantissa);
                    uint  r = ((uint)v.mantissa) - 10 * ((uint)q);
                    if (r != 0)
                    {
                        break;
                    }
                    v.mantissa = q;
                    ++v.exponent;
                }
            }
            else
            {
                v = d2d(ieeeMantissa, ieeeExponent);
            }

            return(to_chars(v, ieeeSign, result));
        }
Beispiel #2
0
        static bool d2d_small_int(ulong ieeeMantissa, uint ieeeExponent,
                                  ref floating_decimal_64 v)
        {
            ulong m2 = (1ul << DOUBLE_MANTISSA_BITS) | ieeeMantissa;
            int   e2 = (int)ieeeExponent - DOUBLE_BIAS - DOUBLE_MANTISSA_BITS;

            if (e2 > 0)
            {
                // f = m2 * 2^e2 >= 2^53 is an integer.
                // Ignore this case for now.
                return(false);
            }

            if (e2 < -52)
            {
                // f < 1.
                return(false);
            }

            // Since 2^52 <= m2 < 2^53 and 0 <= -e2 <= 52: 1 <= f = m2 / 2^-e2 < 2^53.
            // Test if the lower -e2 bits of the significand are 0, i.e. whether the fraction is 0.
            ulong mask     = (1ul << -e2) - 1;
            ulong fraction = m2 & mask;

            if (fraction != 0)
            {
                return(false);
            }

            // f is an integer in the range [1, 2^53).
            // Note: mantissa might contain trailing (decimal) 0's.
            // Note: since 2^53 < 10^16, there is no need to adjust decimalLength17().
            v.mantissa = m2 >> -e2;
            v.exponent = 0;
            return(true);
        }
Beispiel #3
0
        static int to_chars(floating_decimal_64 v, bool sign, Span <char> result)
        {
            // Step 5: Print the decimal representation.
            int index = 0;

            if (sign)
            {
                result[index++] = '-';
            }

            ulong output  = v.mantissa;
            int   olength = decimalLength17(output);

            // Print the decimal digits.
            // The following code is equivalent to:
            // for (uint i = 0; i < olength - 1; ++i) {
            //    uint c = output % 10; output /= 10;
            //   result[index + olength - i] = (char) ('0' + c);
            // }
            // result[index] = '0' + output % 10;

            int i = 0;
            // We prefer 32-bit operations, even on 64-bit platforms.
            // We have at most 17 digits, and uint can store 9 digits.
            // If output doesn't fit into uint, we cut off 8 digits,
            // so the rest will fit into uint.
            uint output2;

            if ((output >> 32) != 0)
            {
                // Expensive 64-bit division.
                ulong q = div1e8(output);
                output2 = ((uint)output) - 100000000 * ((uint)q);
                output  = q;

                uint c = output2 % 10000;
                output2 /= 10000;
                uint d  = output2 % 10000;
                uint c0 = (c % 100) << 1;
                uint c1 = (c / 100) << 1;
                uint d0 = (d % 100) << 1;
                uint d1 = (d / 100) << 1;
                memcpy(result.Slice(index + olength - i - 1), DIGIT_TABLE, c0, 2);
                memcpy(result.Slice(index + olength - i - 3), DIGIT_TABLE, c1, 2);
                memcpy(result.Slice(index + olength - i - 5), DIGIT_TABLE, d0, 2);
                memcpy(result.Slice(index + olength - i - 7), DIGIT_TABLE, d1, 2);
                i += 8;
            }
            output2 = (uint)output;
            while (output2 >= 10000)
            {
                uint c = output2 % 10000;
                output2 /= 10000;
                uint c0 = (c % 100) << 1;
                uint c1 = (c / 100) << 1;
                memcpy(result.Slice(index + olength - i - 1), DIGIT_TABLE, c0, 2);
                memcpy(result.Slice(index + olength - i - 3), DIGIT_TABLE, c1, 2);
                i += 4;
            }
            if (output2 >= 100)
            {
                uint c = (output2 % 100) << 1;
                output2 /= 100;
                memcpy(result.Slice(index + olength - i - 1), DIGIT_TABLE, c, 2);
                i += 2;
            }
            if (output2 >= 10)
            {
                uint c = output2 << 1;
                // We can't use memcpy here: the decimal dot goes between these two digits.
                result[index + olength - i] = DIGIT_TABLE[c + 1];
                result[index] = DIGIT_TABLE[c];
            }
            else
            {
                result[index] = (char)('0' + output2);
            }

            // Print decimal point if needed.
            if (olength > 1)
            {
                result[index + 1] = '.';
                index            += olength + 1;
            }
            else
            {
                ++index;
            }

            // Print the exponent.
            result[index++] = 'E';
            int exp = v.exponent + (int)olength - 1;

            if (exp < 0)
            {
                result[index++] = '-';
                exp             = -exp;
            }

            if (exp >= 100)
            {
                int c = exp % 10;
                memcpy(result.Slice(index), DIGIT_TABLE, 2 * (exp / 10), 2);
                result[index + 2] = (char)('0' + c);
                index            += 3;
            }
            else if (exp >= 10)
            {
                memcpy(result.Slice(index), DIGIT_TABLE, 2 * exp, 2);
                index += 2;
            }
            else
            {
                result[index++] = (char)('0' + exp);
            }

            return(index);
        }