Double to string conversion without scientific notation
Asked Answered
S

18

105

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.

Saarinen answered 9/10, 2009 at 21:25 Comment(2)
do you have a solution for this question now?Kappel
@Anand, there are two solutions which work (Paul Sasik and mine) even if they are not overly "nice" (going through string manipulation).Saarinen
F
56

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).

Forepeak answered 13/11, 2015 at 16:26 Comment(3)
Nice and pretty short, but if you don't need extremely large values, you could do 10x faster. See my answer: https://mcmap.net/q/204370/-double-to-string-conversion-without-scientific-notationRachal
Thank you, worked perfectly. You are a wonderful human being. Upvoted.Triumph
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.Recitativo
M
36

I had a similar problem and this worked for me:

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

F99 may be overkill, but you get the idea.

Mylesmylitta answered 11/8, 2011 at 20:45 Comment(3)
99 is not enough, and it has to work for both before and behind the comma.Saarinen
TrimEnd('0') is sufficient, because the char array is params. That is, any chars passed to TrimEnd will be automatically grouped into an array.Calamint
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.Forepeak
W
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();
    }
}
Weeper answered 15/10, 2009 at 2:43 Comment(13)
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.Weeper
Not yet, will do it soon... ;)Saarinen
This one is more easily read, as you don't have to grok the regex.Snowbound
+1 LOL @ "grok the regex" i love it. i will make it part of my development vernacular! Thanks.Weeper
Well, the Regex one at least has nicely named groups instead of unspecific indexes in some arrays... ;)Saarinen
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.Antemeridian
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().Antemeridian
Why wouldn't you use the simpler doubleValue.ToString("0." + new string('#', 339))? Less bugs, better performance.Forepeak
@Forepeak 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.Southwards
@Southwards 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). GistForepeak
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.Forepeak
In 64-bit apps, yours is 38.05% slower for double.Epsilon and 250.00% faster for e-0.Forepeak
This code should use String strOrig = input.ToString("r");Recitativo
R
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.

Rachal answered 24/3, 2016 at 15:49 Comment(3)
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.Saarinen
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.Forepeak
This is a pretty good solution given that you know the value rangeGallman
S
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));
Saarinen answered 9/10, 2009 at 21:34 Comment(14)
-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.Bearwood
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.Saarinen
Find a way to calculate 1e-200 on runtime instead of setting a "constant" value, i will vote it up.Bearwood
No problem. double x = 1.0; for (int i = 0; i < 200; i++) x /= 10; Console.WriteLine(x);Saarinen
@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.Bearwood
By the way can you add double x stuff with editing your answer? I cannot vote up (I want to).Bearwood
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.Saarinen
So 1e-200 + 1e-199 can be converted to string by the method you provide. I got it. Thank you very very much.Bearwood
You're welcome, and thank you for being open to the discussion. :)Saarinen
I always bow down to the knowledge :)Bearwood
string test = ((double)0.00000007).ToString("f20"); the number (20) may varySural
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.Amateur
@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.Saarinen
@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.Saarinen
R
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();
            }
        }
    }
}
Recitativo answered 5/4, 2018 at 3:1 Comment(3)
According to .NET documentation, double.ToString("G17") is better than double.ToString("r")Verduzco
@Verduzco I disagree about using G17. In their own example, 0.6822871999174.ToString("G17") outputs: 0.68228719991739994.Recitativo
Here are two links discussing the issues with double.Parse(...): github.com/dotnet/runtime/issues/4406 and github.com/dotnet/roslyn/issues/4221Recitativo
S
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#.

Shirleneshirley answered 14/10, 2009 at 18:34 Comment(3)
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)...Saarinen
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.Saarinen
Hello! I've come here from 10 years in the future to let you know that the hyperlink to Jon's article has broken.Gensler
S
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.

Selfinductance answered 14/10, 2009 at 20:28 Comment(1)
Thanks for the input, I'll try to implement a fully working solution like this and compare it to mine.Saarinen
F
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

Filum answered 11/4, 2012 at 11:41 Comment(0)
L
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;
}
Lotion answered 14/10, 2009 at 22:41 Comment(0)
N
1
string strdScaleFactor = dScaleFactor.ToString(); // where dScaleFactor = 3.531467E-05

decimal decimalScaleFactor = Decimal.Parse(strdScaleFactor, System.Globalization.NumberStyles.Float);
Numbskull answered 17/3, 2017 at 9:18 Comment(2)
Could you explain briefly what this code does and how it's different from the other 15 or so answers?Strother
Welcome to Stack Overflow! While this code snippet may solve the question, including an explanation 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!Pneumonia
G
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)

Gaekwar answered 18/10, 2009 at 21:0 Comment(1)
This is the same as already posted by ebpower, see the comments there... ;)Saarinen
P
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

Poncho answered 24/7, 2021 at 14:16 Comment(0)
A
-1

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

data.ToString("n");

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

Aniseikonia answered 9/10, 2009 at 21:39 Comment(3)
Seeing your answer I must have misunderstood your question, sorry.Aniseikonia
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: msdn.microsoft.com/en-us/library/dwhawy9k.aspx#NFormatStringSaarinen
You can also add more after the decimal place (i.e. "n8", or "n50", etc).Poulenc
M
-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);
Menjivar answered 27/10, 2010 at 10:12 Comment(1)
That doesn't even compile, can you post something that compiles?Saarinen
R
-1

My solution was using the custom formats. try this:

double d;
d = 1234.12341234;
d.ToString("#########0.#########");
Richel answered 14/2, 2012 at 13:31 Comment(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.Saarinen
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.Forepeak
I
-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.

Isaiah answered 9/10, 2009 at 22:35 Comment(1)
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.Saarinen
F
-2

This works fine for me...

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

//Output: "150000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
Fairfax answered 22/5, 2012 at 11:16 Comment(1)
Yes, it works for large numbers, but not for anything behind the comma, especially not something like 1.5e-200.Saarinen

© 2022 - 2024 — McMap. All rights reserved.