Exemple #1
0
        static ParseError Base10ToBase2(ref float output, ulong mantissa10, int exponent10)
        {
            if (mantissa10 == 0)
            {
                output = 0.0f;
                return(ParseError.None);
            }
            if (exponent10 == 0)
            {
                output = mantissa10;
                return(ParseError.None);
            }
            var exponent2 = exponent10;
            var mantissa2 = mantissa10;

            while (exponent10 > 0)
            {
                while ((mantissa2 & 0xe000000000000000U) != 0)
                {
                    mantissa2 >>= 1;
                    ++exponent2;
                }
                mantissa2 *= 5;
                --exponent10;
            }
            while (exponent10 < 0)
            {
                while ((mantissa2 & 0x8000000000000000U) == 0)
                {
                    mantissa2 <<= 1;
                    --exponent2;
                }
                mantissa2 /= 5;
                ++exponent10;
            }
            // TODO: implement math.ldexpf (which presumably handles denormals (i don't))
            UintFloatUnion ufu = new UintFloatUnion();

            ufu.floatValue = mantissa2;
            var e = (int)((ufu.uintValue >> 23) & 0xFFU) - 127;

            e += exponent2;
            if (e > 128)
            {
                return(ParseError.Overflow);
            }
            if (e < -127)
            {
                return(ParseError.Underflow);
            }
            ufu.uintValue = (ufu.uintValue & ~(0xFFU << 23)) | ((uint)(e + 127) << 23);
            output        = ufu.floatValue;
            return(ParseError.None);
        }
Exemple #2
0
        public static void Base2ToBase10(ref ulong mantissa10, ref int exponent10, float input)
        {
            UintFloatUnion ufu = new UintFloatUnion();

            ufu.floatValue = input;
            if (ufu.uintValue == 0)
            {
                mantissa10 = 0;
                exponent10 = 0;
                return;
            }
            var mantissa2 = (ufu.uintValue & ((1 << 23) - 1)) | (1 << 23);
            var exponent2 = (int)(ufu.uintValue >> 23) - 127 - 23;

//            var tz = tzcnt((uint)mantissa2);
//            mantissa2 >>= tz;
//            exponent2 += tz;
            mantissa10 = mantissa2;
            exponent10 = exponent2;
            if (exponent2 > 0)
            {
                while (exponent2 > 0)
                {
                    // denormalize mantissa10 as much as you can, to minimize loss when doing /5 below.
                    while (mantissa10 <= UInt64.MaxValue / 10)
                    {
                        mantissa10 *= 10;
                        --exponent10;
                    }
                    mantissa10 /= 5;
                    --exponent2;
                }
            }
            if (exponent2 < 0)
            {
                while (exponent2 < 0)
                {
                    // normalize mantissa10 just as much as you need, in order to make the *5 below not overflow.
                    while (mantissa10 > UInt64.MaxValue / 5)
                    {
                        mantissa10 /= 10;
                        ++exponent10;
                    }
                    mantissa10 *= 5;
                    ++exponent2;
                }
            }
            // normalize mantissa10
            while (mantissa10 > 9999999U || mantissa10 % 10 == 0)
            {
                mantissa10 = (mantissa10 + 5) / 10;
                ++exponent10;
            }
        }
Exemple #3
0
        public ParseError Parse(ref int offset, ref float output, char decimalSeparator)
        {
            if (Found(ref offset, 'n', 'a', 'n'))
            {
                UintFloatUnion ufu = new UintFloatUnion();
                ufu.uintValue = 4290772992U;
                output        = ufu.floatValue;
                return(ParseError.None);
            }
            int sign = 1;

            if (offset < Length)
            {
                if (buffer[offset] == '+')
                {
                    ++offset;
                }
                else if (buffer[offset] == '-')
                {
                    sign = -1;
                    ++offset;
                }
            }
            ulong decimalMantissa   = 0;
            int   significantDigits = 0;
            int   digitsAfterDot    = 0;
            int   mantissaDigits    = 0;

            if (Found(ref offset, 'i', 'n', 'f', 'i', 'n', 'i', 't', 'y'))
            {
                output = (sign == 1) ? Single.PositiveInfinity : Single.NegativeInfinity;
                return(ParseError.None);
            }
            while (offset < Length && IsDigit(buffer[offset]))
            {
                ++mantissaDigits;
                if (significantDigits < 9)
                {
                    var temp = decimalMantissa * 10 + (ulong)(buffer[offset] - '0');
                    if (temp > decimalMantissa)
                    {
                        ++significantDigits;
                    }
                    decimalMantissa = temp;
                }
                else
                {
                    --digitsAfterDot;
                }
                ++offset;
            }
            if (offset < Length && buffer[offset] == decimalSeparator)
            {
                ++offset;
                while (offset < Length && IsDigit(buffer[offset]))
                {
                    ++mantissaDigits;
                    if (significantDigits < 9)
                    {
                        var temp = decimalMantissa * 10 + (ulong)(buffer[offset] - '0');
                        if (temp > decimalMantissa)
                        {
                            ++significantDigits;
                        }
                        decimalMantissa = temp;
                        ++digitsAfterDot;
                    }
                    ++offset;
                }
            }
            if (mantissaDigits == 0)
            {
                return(ParseError.Syntax);
            }
            int decimalExponent     = 0;
            int decimalExponentSign = 1;

            if (offset < Length && ((buffer[offset] | 32) == 'e'))
            {
                ++offset;
                if (offset < Length)
                {
                    if (buffer[offset] == '+')
                    {
                        ++offset;
                    }
                    else if (buffer[offset] == '-')
                    {
                        decimalExponentSign = -1;
                        ++offset;
                    }
                }
                int exponentDigits = 0;
                while (offset < Length && IsDigit(buffer[offset]))
                {
                    ++exponentDigits;
                    decimalExponent = decimalExponent * 10 + (buffer[offset] - '0');
                    if (decimalExponent > 38)
                    {
                        if (decimalExponentSign == 1)
                        {
                            return(ParseError.Overflow);
                        }
                        else
                        {
                            return(ParseError.Underflow);
                        }
                    }
                    ++offset;
                }
                if (exponentDigits == 0)
                {
                    return(ParseError.Syntax);
                }
            }
            decimalExponent = decimalExponent * decimalExponentSign - digitsAfterDot;
            var error = Base10ToBase2(ref output, decimalMantissa, decimalExponent);

            if (error != ParseError.None)
            {
                return(error);
            }
            output *= sign;
            return(ParseError.None);
        }
Exemple #4
0
        public FormatError Format(float input, char decimalSeparator)
        {
            UintFloatUnion ufu = new UintFloatUnion();

            ufu.floatValue = input;
            if (ufu.uintValue == 4290772992U)
            {
                return(Format('N', 'a', 'N'));
            }
            var sign = ufu.uintValue >> 31;

            ufu.uintValue &= ~(1 << 31);
            FormatError error;

            if (sign != 0 && ufu.uintValue != 0) // C# prints -0 as 0
            {
                if ((error = Format('-')) != FormatError.None)
                {
                    return(error);
                }
            }
            if (ufu.uintValue == 2139095040U)
            {
                return(Format('I', 'n', 'f', 'i', 'n', 'i', 't', 'y'));
            }
            ulong decimalMantissa = 0;
            int   decimalExponent = 0;

            Base2ToBase10(ref decimalMantissa, ref decimalExponent, ufu.floatValue);
            var backwards     = stackalloc char[9];
            int decimalDigits = 0;

            do
            {
                if (decimalDigits >= 9)
                {
                    return(FormatError.Overflow);
                }
                var decimalDigit = decimalMantissa % 10;
                backwards[8 - decimalDigits++] = (char)('0' + decimalDigit);
                decimalMantissa /= 10;
            } while (decimalMantissa > 0);
            char *ascii         = backwards + 9 - decimalDigits;
            var   leadingZeroes = -decimalExponent - decimalDigits + 1;

            if (leadingZeroes > 0)
            {
                if (leadingZeroes > 4)
                {
                    return(FormatScientific(ascii, decimalDigits, decimalExponent, decimalSeparator));
                }
                if ((error = Format('0', decimalSeparator)) != FormatError.None)
                {
                    return(error);
                }
                --leadingZeroes;
                while (leadingZeroes > 0)
                {
                    if ((error = Format('0')) != FormatError.None)
                    {
                        return(error);
                    }
                    --leadingZeroes;
                }
                for (var i = 0; i < decimalDigits; ++i)
                {
                    if ((error = Format(ascii[i])) != FormatError.None)
                    {
                        return(error);
                    }
                }
                return(FormatError.None);
            }
            var trailingZeroes = decimalExponent;

            if (trailingZeroes > 0)
            {
                if (trailingZeroes > 4)
                {
                    return(FormatScientific(ascii, decimalDigits, decimalExponent, decimalSeparator));
                }
                for (var i = 0; i < decimalDigits; ++i)
                {
                    if ((error = Format(ascii[i])) != FormatError.None)
                    {
                        return(error);
                    }
                }
                while (trailingZeroes > 0)
                {
                    if ((error = Format('0')) != FormatError.None)
                    {
                        return(error);
                    }
                    --trailingZeroes;
                }
                return(FormatError.None);
            }
            var indexOfSeparator = decimalDigits + decimalExponent;

            for (var i = 0; i < decimalDigits; ++i)
            {
                if (i == indexOfSeparator)
                {
                    if ((error = Format(decimalSeparator)) != FormatError.None)
                    {
                        return(error);
                    }
                }
                if ((error = Format(ascii[i])) != FormatError.None)
                {
                    return(error);
                }
            }
            return(FormatError.None);
        }