103

How to convert a double into a floating-point string representation without scientific notation in the .NET Framework?

"Small" samples (effective numbers may be of any size, such as 1.5E200 or 1e-200) :

3248971234698200000000000000000000000000000000
0.00000000000000000000000000000000000023897356978234562

None of the standard number formats are like this, and a custom format also doesn't seem to allow having an open number of digits after the decimal separator.

This is not a duplicate of How to convert double to string without the power to 10 representation (E-05) because the answers given there do not solve the issue at hand. The accepted solution in this question was to use a fixed point (such as 20 digits), which is not what I want. A fixed point formatting and trimming the redundant 0 doesn't solve the issue either because the max width for fixed width is 99 characters.

Note: the solution has to deal correctly with custom number formats (e.g. other decimal separator, depending on culture information).

Edit: The question is really only about displaing aforementioned numbers. I'm aware of how floating point numbers work and what numbers can be used and computed with them.

Community
  • 1
  • 1
Lucero
  • 59,176
  • 9
  • 122
  • 152
  • 1
    do you have a solution for this question now? – Kira Jun 05 '15 at 09:59
  • @Anand, there are two solutions which work (Paul Sasik and mine) even if they are not overly "nice" (going through string manipulation). – Lucero Jun 05 '15 at 10:32

18 Answers18

54

For a general-purpose¹ solution you need to preserve 339 places:

doubleValue.ToString("0." + new string('#', 339))

The maximum number of non-zero decimal digits is 16. 15 are on the right side of the decimal point. The exponent can move those 15 digits a maximum of 324 places to the right. (See the range and precision.)

It works for double.Epsilon, double.MinValue, double.MaxValue, and anything in between.

The performance will be much greater than the regex/string manipulation solutions since all formatting and string work is done in one pass by unmanaged CLR code. Also, the code is much simpler to prove correct.

For ease of use and even better performance, make it a constant:

public static class FormatStrings
{
    public const string DoubleFixedPoint = "0.###################################################################################################################################################################################################################################################################################################################################################";
}

¹ Update: I mistakenly said that this was also a lossless solution. In fact it is not, since ToString does its normal display rounding for all formats except r. Live example. Thanks, @Loathing! Please see Lothing’s answer if you need the ability to roundtrip in fixed point notation (i.e, if you’re using .ToString("r") today).

jnm2
  • 7,960
  • 5
  • 61
  • 99
  • Nice and pretty short, but if you don't need extremely large values, you could do 10x faster. See my answer: http://stackoverflow.com/a/36204442/143684 – ygoe Mar 24 '16 at 16:03
  • Thank you, worked perfectly. You are a wonderful human being. Upvoted. – Snoop Oct 27 '16 at 12:40
  • 1
    This solution is not "loseless". Example: `String t1 = (0.0001/7).ToString("0." + new string('#', 339)); // 0.0000142857142857143` versus: `String t2 = (0.0001/7).ToString("r"); // 1.4285714285714287E-05` Precision is lost at the ending decimal places. – Loathing Apr 05 '18 at 02:46
34

I had a similar problem and this worked for me:

doubleValue.ToString("F99").TrimEnd('0')

F99 may be overkill, but you get the idea.

Pyritie
  • 543
  • 4
  • 16
Robert Lamm
  • 373
  • 3
  • 2
  • 1
    99 is not enough, *and* it has to work for both before and behind the comma. – Lucero Aug 11 '11 at 21:13
  • 2
    `TrimEnd('0')` is sufficient, because the `char` array is `params`. That is, any `char`s passed to `TrimEnd` will be automatically grouped into an array. – Grault May 15 '15 at 15:24
  • 99 is *not* enough for a general-purpose solution. `doubleValue.ToString("0." + new string('#', 339))` is lossless. Compare these methods using the value [`double.Epsilon`](https://msdn.microsoft.com/en-us/library/system.double.epsilon.aspx). – jnm2 Nov 13 '15 at 16:19
22

This is a string parsing solution where the source number (double) is converted into a string and parsed into its constituent components. It is then reassembled by rules into the full-length numeric representation. It also accounts for locale as requested.

Update: The tests of the conversions only include single-digit whole numbers, which is the norm, but the algorithm also works for something like: 239483.340901e-20

using System;
using System.Text;
using System.Globalization;
using System.Threading;

public class MyClass
{
    public static void Main()
    {
        Console.WriteLine(ToLongString(1.23e-2));            
        Console.WriteLine(ToLongString(1.234e-5));           // 0.00010234
        Console.WriteLine(ToLongString(1.2345E-10));         // 0.00000001002345
        Console.WriteLine(ToLongString(1.23456E-20));        // 0.00000000000000000100023456
        Console.WriteLine(ToLongString(5E-20));
        Console.WriteLine("");
        Console.WriteLine(ToLongString(1.23E+2));            // 123
        Console.WriteLine(ToLongString(1.234e5));            // 1023400
        Console.WriteLine(ToLongString(1.2345E10));          // 1002345000000
        Console.WriteLine(ToLongString(-7.576E-05));         // -0.00007576
        Console.WriteLine(ToLongString(1.23456e20));
        Console.WriteLine(ToLongString(5e+20));
        Console.WriteLine("");
        Console.WriteLine(ToLongString(9.1093822E-31));        // mass of an electron
        Console.WriteLine(ToLongString(5.9736e24));            // mass of the earth 

        Console.ReadLine();
    }

    private static string ToLongString(double input)
    {
        string strOrig = input.ToString();
        string str = strOrig.ToUpper();

        // if string representation was collapsed from scientific notation, just return it:
        if (!str.Contains("E")) return strOrig;

        bool negativeNumber = false;

        if (str[0] == '-')
        {
            str = str.Remove(0, 1);
            negativeNumber = true;
        }

        string sep = Thread.CurrentThread.CurrentCulture.NumberFormat.NumberDecimalSeparator;
        char decSeparator = sep.ToCharArray()[0];

        string[] exponentParts = str.Split('E');
        string[] decimalParts = exponentParts[0].Split(decSeparator);

        // fix missing decimal point:
        if (decimalParts.Length==1) decimalParts = new string[]{exponentParts[0],"0"};

        int exponentValue = int.Parse(exponentParts[1]);

        string newNumber = decimalParts[0] + decimalParts[1];

        string result;

        if (exponentValue > 0)
        {
            result = 
                newNumber + 
                GetZeros(exponentValue - decimalParts[1].Length);
        }
        else // negative exponent
        {
            result = 
                "0" + 
                decSeparator + 
                GetZeros(exponentValue + decimalParts[0].Length) + 
                newNumber;

            result = result.TrimEnd('0');
        }

        if (negativeNumber)
            result = "-" + result;

        return result;
    }

    private static string GetZeros(int zeroCount)
    {
        if (zeroCount < 0) 
            zeroCount = Math.Abs(zeroCount);

        StringBuilder sb = new StringBuilder();

        for (int i = 0; i < zeroCount; i++) sb.Append("0");    

        return sb.ToString();
    }
}
Ed Avis
  • 1,350
  • 17
  • 36
Paul Sasik
  • 79,492
  • 20
  • 149
  • 189
  • Huh. Honestly, i noticed that it got voted down so i didn't examine the code very closely. i did read it just now and you're right. They are close, i just chose to not use RegEx in my process and did my own string parsing. Have you tested this solution? It's a complete console app. – Paul Sasik Oct 15 '09 at 11:29
  • Not yet, will do it soon... ;) – Lucero Oct 15 '09 at 15:11
  • 3
    This one is more easily read, as you don't have to grok the regex. – Gregory Oct 15 '09 at 21:52
  • +1 LOL @ "grok the regex" i love it. i will make it part of my development vernacular! Thanks. – Paul Sasik Oct 15 '09 at 22:23
  • Well, the Regex one at least has nicely named groups instead of unspecific indexes in some arrays... ;) – Lucero Oct 16 '09 at 13:08
  • I think you could simplify slightly by using the `InvariantCulture` on the initial `ToString` call. That lets you assume the separator is `.` and makes sure your code still works even in truly weird locales where the decimal separator is more than one character long. – Ed Avis Oct 23 '15 at 15:28
  • Another improvement would be to make an extension method: `public static class MyClass` and then `public static string ToLongString(this double input)`. That lets you call `d.ToLongString()` in the same way you can call `d.ToString()`. – Ed Avis Oct 23 '15 at 15:40
  • Why wouldn't you use the simpler `doubleValue.ToString("0." + new string('#', 339))`? Less bugs, better performance. – jnm2 Nov 13 '15 at 16:33
  • @jnm2 Actually I tested that it is ~20% faster than `doubleValue.ToString("0." + new string('#', 339))` for worst-case scenarios (E-320). For numbers not needing scientific notation, it is ~300% faster. – hannesRSA Feb 01 '16 at 13:11
  • @hannesRSA I'm not able to duplicate your benchmark. With `double.Epsilon`, yours is 7.85% slower than `doubleValue.ToString("0." + new string('#', 339))` and 11.44% slower than `doubleValue.ToString(constFormatString)`. [Gist](https://gist.github.com/jnm2/7b038093101033f12954) – jnm2 Feb 01 '16 at 13:39
  • In fairness, the break-even point is numbers in the range `e-255` which is surprising to me since you're running native code in both scenarios and managed code on top of that in your scenario. Native formatting is slower than your method for larger numbers; yours is 417.66% faster for `e-0` numbers. I still stand by the flexibility and simplicity of the fool-proof format string method, however. – jnm2 Feb 01 '16 at 13:50
  • In 64-bit apps, yours is 38.05% slower for `double.Epsilon` and 250.00% faster for `e-0`. – jnm2 Feb 01 '16 at 13:56
  • This code should use `String strOrig = input.ToString("r");` – Loathing Apr 05 '18 at 03:16
20

You could cast the double to decimal and then do ToString().

(0.000000005).ToString()   // 5E-09
((decimal)(0.000000005)).ToString()   // 0,000000005

I haven't done performance testing which is faster, casting from 64-bit double to 128-bit decimal or a format string of over 300 chars. Oh, and there might possibly be overflow errors during conversion, but if your values fit a decimal this should work fine.

Update: The casting seems to be a lot faster. Using a prepared format string as given in the other answer, formatting a million times takes 2.3 seconds and casting only 0.19 seconds. Repeatable. That's 10x faster. Now it's only about the value range.

ygoe
  • 18,655
  • 23
  • 113
  • 210
  • This does unfortunately not work for the given specification of very large or small numbers. `((decimal)(1e-200)).ToString()` for instance returns `0` which is wrong. – Lucero Mar 24 '16 at 16:05
  • 1
    To be fair and compare apples to apples, you should be comparing this method to `double.ToString("0.############################")`. According to my test, yours is only 3x faster. Either way it's only a valid answer if you know for sure that you don't need to print digits below `1e-28` and that your double is not large, both of which are not constraints in the original question. – jnm2 Mar 24 '16 at 16:28
  • 2
    This is a pretty good solution given that you know the value range – Artur Udod Nov 09 '17 at 16:14
8

This is what I've got so far, seems to work, but maybe someone has a better solution:

private static readonly Regex rxScientific = new Regex(@"^(?<sign>-?)(?<head>\d+)(\.(?<tail>\d*?)0*)?E(?<exponent>[+\-]\d+)$", RegexOptions.IgnoreCase|RegexOptions.ExplicitCapture|RegexOptions.CultureInvariant);

public static string ToFloatingPointString(double value) {
    return ToFloatingPointString(value, NumberFormatInfo.CurrentInfo);
}

public static string ToFloatingPointString(double value, NumberFormatInfo formatInfo) {
    string result = value.ToString("r", NumberFormatInfo.InvariantInfo);
    Match match = rxScientific.Match(result);
    if (match.Success) {
        Debug.WriteLine("Found scientific format: {0} => [{1}] [{2}] [{3}] [{4}]", result, match.Groups["sign"], match.Groups["head"], match.Groups["tail"], match.Groups["exponent"]);
        int exponent = int.Parse(match.Groups["exponent"].Value, NumberStyles.Integer, NumberFormatInfo.InvariantInfo);
        StringBuilder builder = new StringBuilder(result.Length+Math.Abs(exponent));
        builder.Append(match.Groups["sign"].Value);
        if (exponent >= 0) {
            builder.Append(match.Groups["head"].Value);
            string tail = match.Groups["tail"].Value;
            if (exponent < tail.Length) {
                builder.Append(tail, 0, exponent);
                builder.Append(formatInfo.NumberDecimalSeparator);
                builder.Append(tail, exponent, tail.Length-exponent);
            } else {
                builder.Append(tail);
                builder.Append('0', exponent-tail.Length);
            }
        } else {
            builder.Append('0');
            builder.Append(formatInfo.NumberDecimalSeparator);
            builder.Append('0', (-exponent)-1);
            builder.Append(match.Groups["head"].Value);
            builder.Append(match.Groups["tail"].Value);
        }
        result = builder.ToString();
    }
    return result;
}

// test code
double x = 1.0;
for (int i = 0; i < 200; i++) {
    x /= 10;
}
Console.WriteLine(x);
Console.WriteLine(ToFloatingPointString(x));
Lucero
  • 59,176
  • 9
  • 122
  • 152
  • -1 since does not provide solution for the following stuation (and it cannot): double d1 = 1e-200; d = d + 1; ToFloatingPointString(d) just returns 1 here. Not 1,000...........000001. – JCasso Oct 10 '09 at 00:14
  • 5
    Adding one to a very small double is just your idea, and has nothing to do with the question at hand. If you just run it without the d=d+1, you'll see that it does in fact display 0.000.....0001. – Lucero Oct 10 '09 at 00:24
  • Find a way to calculate 1e-200 on runtime instead of setting a "constant" value, i will vote it up. – JCasso Oct 10 '09 at 00:33
  • 2
    No problem. `double x = 1.0; for (int i = 0; i < 200; i++) x /= 10; Console.WriteLine(x);` – Lucero Oct 10 '09 at 00:45
  • @Lucero: That's it. Works perfect. This post is also the answer of your question. I am sorry for the misinformation i provided. However I really don't understand why division works but putting 1 does not work here. – JCasso Oct 10 '09 at 00:49
  • By the way can you add double x stuff with editing your answer? I cannot vote up (I want to). – JCasso Oct 10 '09 at 00:50
  • 6
    That's because only 15 digits are in fact meaningful, but you can "shift" them with the exponent to be very large or very small. But you cannot add a very small number with a number which is more than about 15 digits larger, because doing so exceeds the number of significant digits and since the larger number is more significant, the small portion will be lost. Therefore, computing with numbers in a similar range (like adding 1e-200 and 1e-200, or 1+1, or 1e200+1e200) does work, but mixing such values will result in rounding the smaller value away. – Lucero Oct 10 '09 at 00:54
  • So 1e-200 + 1e-199 can be converted to string by the method you provide. I got it. Thank you very very much. – JCasso Oct 10 '09 at 00:59
  • You're welcome, and thank you for being open to the discussion. :) – Lucero Oct 10 '09 at 01:01
  • I always bow down to the knowledge :) – JCasso Oct 10 '09 at 01:06
  • string test = ((double)0.00000007).ToString("f20"); the number (20) may vary – Radu M. Mar 09 '12 at 09:32
  • The solution "double x = 1.0; for (int i = 0; i < 200; i++) x /= 10; Console.WriteLine(x);" suffers from impression in the result because cumulative division by an inexact value accumulates the errors in the result. A better solution is to reduce the number of divisions so that the cumulative error is reduced. For example, if you need to divide by powers of 10, create an array of powers of 10 by multiples of 10 -- 10, 1e10, 1e100, 1e1000, etc. -- then use those in the loop, decrementing the loop control variable according. For 1e-200, ((1.0 / 1e100) / 1e100) is exact. The other way isn't. – Julie in Austin May 19 '12 at 21:40
  • @Julie, that's actually not a solution, it's just to prove that it is possible to get to numbers that small through computation (and not just by defining a constant value). You're of course right about the inexact value accumulation, but it is irrelevant for this example. – Lucero May 19 '12 at 21:47
  • @JulieinAustin, not at all stupid, but without enough knowledge about how floating-point numbers work. See the 3rd comment (written by JCasso). Also note that your computation is incorrect, `((1.0 / 1e100) / 1e100)` would theoretically compute to `1e-10000` (which is out of range for doubles anyways) and not the wanted `1e-200`. – Lucero May 20 '12 at 13:02
7

The problem using #.###...### or F99 is that it doesn't preserve precision at the ending decimal places, e.g:

String t1 = (0.0001/7).ToString("0." + new string('#', 339)); // 0.0000142857142857143
String t2 = (0.0001/7).ToString("r");                         //      1.4285714285714287E-05

The problem with DecimalConverter.cs is that it is slow. This code is the same idea as Sasik's answer, but twice as fast. Unit test method at bottom.

public static class RoundTrip {

    private static String[] zeros = new String[1000];

    static RoundTrip() {
        for (int i = 0; i < zeros.Length; i++) {
            zeros[i] = new String('0', i);
        }
    }

    private static String ToRoundTrip(double value) {
        String str = value.ToString("r");
        int x = str.IndexOf('E');
        if (x < 0) return str;

        int x1 = x + 1;
        String exp = str.Substring(x1, str.Length - x1);
        int e = int.Parse(exp);

        String s = null;
        int numDecimals = 0;
        if (value < 0) {
            int len = x - 3;
            if (e >= 0) {
                if (len > 0) {
                    s = str.Substring(0, 2) + str.Substring(3, len);
                    numDecimals = len;
                }
                else
                    s = str.Substring(0, 2);
            }
            else {
                // remove the leading minus sign
                if (len > 0) {
                    s = str.Substring(1, 1) + str.Substring(3, len);
                    numDecimals = len;
                }
                else
                    s = str.Substring(1, 1);
            }
        }
        else {
            int len = x - 2;
            if (len > 0) {
                s = str[0] + str.Substring(2, len);
                numDecimals = len;
            }
            else
                s = str[0].ToString();
        }

        if (e >= 0) {
            e = e - numDecimals;
            String z = (e < zeros.Length ? zeros[e] : new String('0', e));
            s = s + z;
        }
        else {
            e = (-e - 1);
            String z = (e < zeros.Length ? zeros[e] : new String('0', e));
            if (value < 0)
                s = "-0." + z + s;
            else
                s = "0." + z + s;
        }

        return s;
    }

    private static void RoundTripUnitTest() {
        StringBuilder sb33 = new StringBuilder();
        double[] values = new [] { 123450000000000000.0, 1.0 / 7, 10000000000.0/7, 100000000000000000.0/7, 0.001/7, 0.0001/7, 100000000000000000.0, 0.00000000001,
         1.23e-2, 1.234e-5, 1.2345E-10, 1.23456E-20, 5E-20, 1.23E+2, 1.234e5, 1.2345E10, -7.576E-05, 1.23456e20, 5e+20, 9.1093822E-31, 5.9736e24, double.Epsilon };

        foreach (int sign in new [] { 1, -1 }) {
            foreach (double val in values) {
                double val2 = sign * val;
                String s1 = val2.ToString("r");
                String s2 = ToRoundTrip(val2);

                double val2_ = double.Parse(s2);
                double diff = Math.Abs(val2 - val2_);
                if (diff != 0) {
                    throw new Exception("Value {0} did not pass ToRoundTrip.".Format2(val.ToString("r")));
                }
                sb33.AppendLine(s1);
                sb33.AppendLine(s2);
                sb33.AppendLine();
            }
        }
    }
}
Loathing
  • 5,109
  • 3
  • 24
  • 35
  • According to [.NET documentation](https://learn.microsoft.com/en-us/dotnet/standard/base-types/standard-numeric-format-strings?redirectedfrom=MSDN#RFormatString), double.ToString("G17") is better than double.ToString("r") – YantingChen May 07 '21 at 06:59
  • @YantingChen I disagree about using `G17`. In their own example, `0.6822871999174.ToString("G17")` outputs: `0.68228719991739994`. – Loathing May 07 '21 at 07:30
  • Here are two links discussing the issues with `double.Parse(...)`: https://github.com/dotnet/runtime/issues/4406 and https://github.com/dotnet/roslyn/issues/4221 – Loathing May 07 '21 at 18:39
3

In the old days when we had to write our own formatters, we'd isolate the mantissa and exponent and format them separately.

In this article by Jon Skeet (https://csharpindepth.com/articles/FloatingPoint) he provides a link to his DoubleConverter.cs routine that should do exactly what you want. Skeet also refers to this at extracting mantissa and exponent from double in c#.

Ed Power
  • 8,310
  • 3
  • 36
  • 42
  • Thanks for the link, I've tried the code from Jon already, however for my purpose it's kind of too exact; for instance, 0.1 does not show as 0.1 (which is technically correct, but not what I'd need)... – Lucero Oct 15 '09 at 11:10
  • Yeah, but you see, the whole point of Jon's code is to display the number EXACTLY and this is kind of too much for my case. Rounding as done by the runtime when doing ToString() is just fine for me, and that's probably also why most solutions proposed here use ToString() as base for further processing. – Lucero Oct 15 '09 at 18:35
  • Hello! I've come here from 10 years in the future to let you know that the hyperlink to Jon's article has broken. – Nick Vaccaro May 31 '19 at 18:47
3

The obligatory Logarithm-based solution. Note that this solution, because it involves doing math, may reduce the accuracy of your number a little bit. Not heavily tested.

private static string DoubleToLongString(double x)
{
    int shift = (int)Math.Log10(x);
    if (Math.Abs(shift) <= 2)
    {
        return x.ToString();
    }

    if (shift < 0)
    {
        double y = x * Math.Pow(10, -shift);
        return "0.".PadRight(-shift + 2, '0') + y.ToString().Substring(2);
    }
    else
    {
        double y = x * Math.Pow(10, 2 - shift);
        return y + "".PadRight(shift - 2, '0');
    }
}

Edit: If the decimal point crosses non-zero part of the number, this algorithm will fail miserably. I tried for simple and went too far.

Brian
  • 25,523
  • 18
  • 82
  • 173
  • Thanks for the input, I'll try to implement a fully working solution like this and compare it to mine. – Lucero Oct 15 '09 at 11:15
2

I have just improvised on the code above to make it work for negative exponential values.

using System;
using System.Text.RegularExpressions;
using System.IO;
using System.Text;
using System.Threading;

namespace ConvertNumbersInScientificNotationToPlainNumbers
{
    class Program
    {
        private static string ToLongString(double input)
        {
            string str = input.ToString(System.Globalization.CultureInfo.InvariantCulture);

            // if string representation was collapsed from scientific notation, just return it:
            if (!str.Contains("E")) return str;

            var positive = true;
            if (input < 0)
            {
                positive = false;
            }

            string sep = Thread.CurrentThread.CurrentCulture.NumberFormat.NumberDecimalSeparator;
            char decSeparator = sep.ToCharArray()[0];

            string[] exponentParts = str.Split('E');
            string[] decimalParts = exponentParts[0].Split(decSeparator);

            // fix missing decimal point:
            if (decimalParts.Length == 1) decimalParts = new string[] { exponentParts[0], "0" };

            int exponentValue = int.Parse(exponentParts[1]);

            string newNumber = decimalParts[0].Replace("-", "").
                Replace("+", "") + decimalParts[1];

            string result;

            if (exponentValue > 0)
            {
                if (positive)
                    result =
                        newNumber +
                        GetZeros(exponentValue - decimalParts[1].Length);
                else

                    result = "-" +
                     newNumber +
                     GetZeros(exponentValue - decimalParts[1].Length);


            }
            else // negative exponent
            {
                if (positive)
                    result =
                        "0" +
                        decSeparator +
                        GetZeros(exponentValue + decimalParts[0].Replace("-", "").
                                   Replace("+", "").Length) + newNumber;
                else
                    result =
                    "-0" +
                    decSeparator +
                    GetZeros(exponentValue + decimalParts[0].Replace("-", "").
                             Replace("+", "").Length) + newNumber;

                result = result.TrimEnd('0');
            }
            float temp = 0.00F;

            if (float.TryParse(result, out temp))
            {
                return result;
            }
            throw new Exception();
        }

        private static string GetZeros(int zeroCount)
        {
            if (zeroCount < 0)
                zeroCount = Math.Abs(zeroCount);

            StringBuilder sb = new StringBuilder();

            for (int i = 0; i < zeroCount; i++) sb.Append("0");

            return sb.ToString();
        }

        public static void Main(string[] args)
        {
            //Get Input Directory.
            Console.WriteLine(@"Enter the Input Directory");
            var readLine = Console.ReadLine();
            if (readLine == null)
            {
                Console.WriteLine(@"Enter the input path properly.");
                return;
            }
            var pathToInputDirectory = readLine.Trim();

            //Get Output Directory.
            Console.WriteLine(@"Enter the Output Directory");
            readLine = Console.ReadLine();
            if (readLine == null)
            {
                Console.WriteLine(@"Enter the output path properly.");
                return;
            }
            var pathToOutputDirectory = readLine.Trim();

            //Get Delimiter.
            Console.WriteLine("Enter the delimiter;");
            var columnDelimiter = (char)Console.Read();

            //Loop over all files in the directory.
            foreach (var inputFileName in Directory.GetFiles(pathToInputDirectory))
            {
                var outputFileWithouthNumbersInScientificNotation = string.Empty;
                Console.WriteLine("Started operation on File : " + inputFileName);

                if (File.Exists(inputFileName))
                {
                    // Read the file
                    using (var file = new StreamReader(inputFileName))
                    {
                        string line;
                        while ((line = file.ReadLine()) != null)
                        {
                            String[] columns = line.Split(columnDelimiter);
                            var duplicateLine = string.Empty;
                            int lengthOfColumns = columns.Length;
                            int counter = 1;
                            foreach (var column in columns)
                            {
                                var columnDuplicate = column;
                                try
                                {
                                    if (Regex.IsMatch(columnDuplicate.Trim(),
                                                      @"^[+-]?[0-9]+(\.[0-9]+)?[E]([+-]?[0-9]+)$",
                                                      RegexOptions.IgnoreCase))
                                    {
                                        Console.WriteLine("Regular expression matched for this :" + column);

                                        columnDuplicate = ToLongString(Double.Parse
                                                                           (column,
                                                                            System.Globalization.NumberStyles.Float));

                                        Console.WriteLine("Converted this no in scientific notation " +
                                                          "" + column + "  to this number " +
                                                          columnDuplicate);
                                    }
                                }
                                catch (Exception)
                                {

                                }
                                duplicateLine = duplicateLine + columnDuplicate;

                                if (counter != lengthOfColumns)
                                {
                                    duplicateLine = duplicateLine + columnDelimiter.ToString();
                                }
                                counter++;
                            }
                            duplicateLine = duplicateLine + Environment.NewLine;
                            outputFileWithouthNumbersInScientificNotation = outputFileWithouthNumbersInScientificNotation + duplicateLine;
                        }

                        file.Close();
                    }

                    var outputFilePathWithoutNumbersInScientificNotation
                        = Path.Combine(pathToOutputDirectory, Path.GetFileName(inputFileName));

                    //Create Directory If it does not exist.
                    if (!Directory.Exists(pathToOutputDirectory))
                        Directory.CreateDirectory(pathToOutputDirectory);

                    using (var outputFile =
                        new StreamWriter(outputFilePathWithoutNumbersInScientificNotation))
                    {
                        outputFile.Write(outputFileWithouthNumbersInScientificNotation);
                        outputFile.Close();
                    }

                    Console.WriteLine("The transformed file is here :" +
                        outputFilePathWithoutNumbersInScientificNotation);
                }
            }
        }
    }
}

This code takes an input directory and based on the delimiter converts all values in scientific notation to numeric format.

Thanks

Ed Avis
  • 1,350
  • 17
  • 36
Egalitarian
  • 2,168
  • 7
  • 24
  • 33
1

try this one:

public static string DoubleToFullString(double value, 
                                        NumberFormatInfo formatInfo)
{
    string[] valueExpSplit;
    string result, decimalSeparator;
    int indexOfDecimalSeparator, exp;

    valueExpSplit = value.ToString("r", formatInfo)
                         .ToUpper()
                         .Split(new char[] { 'E' });

    if (valueExpSplit.Length > 1)
    {
        result = valueExpSplit[0];
        exp = int.Parse(valueExpSplit[1]);
        decimalSeparator = formatInfo.NumberDecimalSeparator;

        if ((indexOfDecimalSeparator 
             = valueExpSplit[0].IndexOf(decimalSeparator)) > -1)
        {
            exp -= (result.Length - indexOfDecimalSeparator - 1);
            result = result.Replace(decimalSeparator, "");
        }

        if (exp >= 0) result += new string('0', Math.Abs(exp));
        else
        {
            exp = Math.Abs(exp);
            if (exp >= result.Length)
            {
                result = "0." + new string('0', exp - result.Length) 
                             + result;
            }
            else
            {
                result = result.Insert(result.Length - exp, decimalSeparator);
            }
        }
    }
    else result = valueExpSplit[0];

    return result;
}
manji
  • 47,442
  • 5
  • 96
  • 103
0

Being millions of programmers world wide, it's always a good practice to try search if someone has bumped into your problem already. Sometimes there's solutions are garbage, which means it's time to write your own, and sometimes there are great, such as the following:

http://www.yoda.arachsys.com/csharp/DoubleConverter.cs

(details: http://www.yoda.arachsys.com/csharp/floatingpoint.html)

Letterman
  • 4,076
  • 5
  • 29
  • 41
0
string strdScaleFactor = dScaleFactor.ToString(); // where dScaleFactor = 3.531467E-05

decimal decimalScaleFactor = Decimal.Parse(strdScaleFactor, System.Globalization.NumberStyles.Float);
JJJ
  • 32,902
  • 20
  • 89
  • 102
Priya
  • 9
  • 1
  • Could you explain briefly what this code does and how it's different from the other 15 or so answers? – JJJ Mar 17 '17 at 10:02
  • Welcome to Stack Overflow! While this code snippet may solve the question, [including an explanation](//meta.stackexchange.com/questions/114762/explaining-entirely-code-based-answers) really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion. Please also try not to crowd your code with explanatory comments, this reduces the readability of both the code and the explanations! – kayess Mar 17 '17 at 11:00
0

I don't know if my answer to the question can still be helpful. But in this case I suggest the "decomposition of the double variable into decimal places" to store it in an Array / Array of data of type String.

This process of decomposition and storage in parts (number by number) from double to string, would basically work with the use of two loops and an "alternative" (if you thought of workaround, I think you got it), where the first loop will extract the values from double without converting to String, resulting in blessed scientific notation and storing number by number in an Array. And this will be done using MOD - the same method to check a palindrome number, which would be for example:

String[] Array_ = new double[ **here you will put an extreme value of places your DOUBLE can reach, you must have a prediction**];

for (int i = 0, variableDoubleMonstrous > 0, i++){
x = variableDoubleMonstrous %10;
Array_[i] = x;
variableDoubleMonstrous /= 10;
}

And the second loop to invert the Array values ​​(because in this process of checking a palindrome, the values ​​invert from the last place, to the first, from the penultimate to the second and so on. Remember?) to get the original value:

String[] ArrayFinal = new String[the same number of "places" / indices of the other Array / Data array];

int lengthArray = Array_.Length;

for (int i = 0, i < Array_.Length, i++){
    FinalArray[i] = Array_[lengthArray - 1];
    lengthArray--;
    }

***Warning: There's a catch that I didn't pay attention to. In that case there will be no "." (floating point decimal separator or double), so this solution is not generalized. But if it is really important to use decimal separators, unfortunately the only possibility (If done well, it will have a great performance) is: **Use a routine to get the position of the decimal point of the original value, the one with scientific notation - the important thing is that you know that this floating point is before a number such as the "Length" position x, and after a number such as the y position - extracting each digit using the loops - as shown above - and at the end "export" the data from the last Array to another one, including the decimal place divider (the comma, or the period , if variable decimal, double or float) in the imaginary position that was in the original variable, in the "real" position of that matrix.

*** The concept of position is, find out how many numbers occur before the decimal point, so with this information you will be able to store in the String Array the point in the real position.

NEEDS THAT CAN BE MADE:

But then you ask:

  • But what about when I'm going to convert String to a floating point value? My answer is that you use the second matrix of this entire process (the one that receives the inversion of the first matrix that obtains the numbers by the palindrome method) and use it for the conversion, but always making sure, when necessary, of the position of the decimal place in future situations, in case this conversion (Double -> String) is needed again.

But what if the problem is to use the value of the converted Double (Array of Strings) in a calculation. Then in this case you went around in circles. Well, the original variable will work anyway even with scientific notation. The only difference between floating point and decimal variable types is in the rounding of values, which depending on the purpose, it will only be necessary to change the type of data used, but it is dangerous to have a significant loss of information, look here

-1

I could be wrong, but isn't it like this?

data.ToString("n");

http://msdn.microsoft.com/en-us/library/dwhawy9k.aspx

csharptest.net
  • 62,602
  • 11
  • 71
  • 89
  • Seeing your answer I must have misunderstood your question, sorry. – csharptest.net Oct 09 '09 at 21:41
  • No, first I don't want the thousand separator and second there seems to be always a fixed number of digits after the comma. See also MSDN help for N format: http://msdn.microsoft.com/en-us/library/dwhawy9k.aspx#NFormatString – Lucero Oct 09 '09 at 21:44
  • You can also add more after the decimal place (i.e. "n8", or "n50", etc). – BrainSlugs83 Apr 10 '13 at 20:49
-1

i think you need only to use IFormat with

ToString(doubleVar, System.Globalization.NumberStyles.Number)

example:

double d = double.MaxValue;
string s = d.ToString(d, System.Globalization.NumberStyles.Number);
abatishchev
  • 98,240
  • 88
  • 296
  • 433
-1

My solution was using the custom formats. try this:

double d;
d = 1234.12341234;
d.ToString("#########0.#########");
  • 2
    Try with the test numbers I gave above: `d = 1.5E200` and `d = 1E-200`. The resulting string should have almost 200 `0` characters in it, or your solution doesn't work. – Lucero Feb 14 '12 at 16:40
  • 9 decimal places is not enough for a general-purpose solution. `doubleValue.ToString("0." + new string('#', 339))` is lossless. Compare these methods using the value [`double.Epsilon`](https://msdn.microsoft.com/en-us/library/system.double.epsilon.aspx). – jnm2 Nov 13 '15 at 16:22
-2

This works fine for me...

double number = 1.5E+200;
string s = number.ToString("#");

//Output: "150000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
  • 1
    Yes, it works for large numbers, but not for anything behind the comma, especially not something like `1.5e-200`. – Lucero May 22 '12 at 20:29
-2

Just to build on what jcasso said what you can do is to adjust your double value by changing the exponent so that your favorite format would do it for you, apply the format, and than pad the result with zeros to compensate for the adjustment.

mfeingold
  • 7,094
  • 4
  • 37
  • 43
  • The exponent in the IEEE floating point numbers is 2-base, but the decimal numbers are 10-base. Therefore, this just doesn't work. This is also the reason why you cannot store 0.1 as exact value in a double. Or please just provide some sample (code) if you think that I misunderstood your answer. – Lucero Oct 09 '09 at 23:16