runtime: Double doesn't Parse correctly

While doing some mathematical stuff that worked fine in Java I found that C# / .NET does a rather poor job on parsing double values:

Number2Parse=4.3413853813852797e+192 IEEE754=67ee7316b1545878 C#=4.3413853813852797E+192
Number2Parse=4.34138538138528e+192 IEEE754=67ee7316b1545878 C#=4.3413853813852797E+192

You can verify in any browser that 4.3413853813852797e+192 and 4.34138538138528e+192 are distinct values. Version: CLR v4.0.30319

using System;

namespace mathbug
{
    class Program
    {
        static void ShowNumber(string number2Parse)
        {
            double d = Double.Parse(number2Parse);
            ulong ieee754 = (ulong)BitConverter.DoubleToInt64Bits(d);
            Console.WriteLine("Number2Parse=" + number2Parse + " IEEE754=" + Convert.ToString((long)ieee754, 16) + " C#=" + d.ToString("G17"));
        }
 
        static void Main(string[] args)
        {
            ShowNumber("4.3413853813852797e+192");
            ShowNumber("4.34138538138528e+192");
        }
    }
}

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Comments: 27 (18 by maintainers)

Most upvoted comments

And it is working as well. SUPER!

@Suchiman My simple test program didn’t take locale in consideration so ‘.’ doesn’t get interpreted as expected in DE.

Double.Parse(number2Parse) must be changed to use invariant locale. Probably like: Double.Parse(number2Parse, NumberStyles.Float, CultureInfo.InvariantCulture)

In case you are interested in 100M test values you may download the following file: https://onedrive.live.com/embed?cid=9341770E0D0D5468&resid=9341770E0D0D5468!222&authkey=ADOClRsuPv3_pTk

Associated test program:

using System;
using System.IO;
using System.Globalization;

namespace mathbug
{
    class Program
    {
        static void Main(string[] args)
        {
            using (StreamReader sr = new StreamReader("c:\\es6\\numbers\\es6testfile100m.txt"))
            {
                string line;
                // Read and display lines from the file until the end of 
                // the file is reached.
                long counter = 0;
                while ((line = sr.ReadLine()) != null)
                {
                    string origIeeeHex = line.Substring(0, line.IndexOf(','));
                    while (origIeeeHex.Length < 16)
                    {
                        origIeeeHex = '0' + origIeeeHex;
                    }
                    ulong origIeeeBin = Convert.ToUInt64(origIeeeHex, 16);
                    double origIeee = BitConverter.Int64BitsToDouble((long)origIeeeBin);
                    string number2Parse = line.Substring(line.IndexOf(',') + 1);
                    if (++counter % 100000 == 0)
                    {
                        Console.WriteLine("Count=" + counter);
                    }
                    double parsedIeee = double.Parse(number2Parse, NumberStyles.Float, CultureInfo.InvariantCulture);
                    String parsedIeeeHex = Convert.ToString(BitConverter.DoubleToInt64Bits(parsedIeee), 16);
                    while (parsedIeeeHex.Length < 16)
                    {
                        parsedIeeeHex = '0' + parsedIeeeHex;
                    }
                    bool roundTripOk = parsedIeee.ToString("G17").Equals(origIeee.ToString("G17"));
                    if (origIeee != parsedIeee || !roundTripOk)
                    {
                        Console.WriteLine("Number2Parse={0,-24:S} C#={1,-24:S} Original=" + origIeeeHex + 
                                          " Parsed=" + parsedIeeeHex +
                                          " Roundtrip OK=" +roundTripOk, number2Parse, origIeee.ToString("G17"));
                    }
                }
            }
        }
    }
}

I am seeing the direction is to port the parsing code from Roslyn to coreclr

This is one possible direction. I think we should do our homework similar to what we have done for formatting. See what is the state of the art out there, and then pick the best option.