Удвойтесь до преобразования строк без экспоненциального представления

Мое эмпирическое правило (хотя не конкретный) - то, что, если я могу использовать тот же код для различных классов, тогда я поместил тот код в родительский класс и использую наследование. Иначе я использую состав.

Это заставляет меня писать меньше кода, который по сути легче поддержать.

71
задан Community 23 May 2017 в 11:54
поделиться

8 ответов

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.

-1
ответ дан 24 November 2019 в 13:05
поделиться

Я могу ошибаться, но разве это не так?

data.ToString("n");

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

-1
ответ дан 24 November 2019 в 13:05
поделиться

попробуйте этот:

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;
}
1
ответ дан 24 November 2019 в 13:05
поделиться

Раньше, когда нам приходилось писать собственные средства форматирования, мы выделяли мантиссу и показатель степени и форматировали их отдельно.

В этой статье Джона Скита ( https : //csharpindepth.com/articles/FloatingPoint ) он предоставляет ссылку на свою подпрограмму DoubleConverter.cs, которая должна делать именно то, что вы хотите. Скит также ссылается на это при извлечении мантиссы и экспоненты из числа double в C # .

3
ответ дан 24 November 2019 в 13:05
поделиться

Поскольку миллионы программистов по всему миру, всегда полезно попробовать поискать, если кто-то уже столкнулся с вашей проблемой. Иногда есть решения - мусор, а это значит, что пора писать свои собственные, а иногда есть отличные, например следующие:

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

( подробности: http://www.yoda.arachsys.com/csharp/floatingpoint.html )

0
ответ дан 24 November 2019 в 13:05
поделиться

Это решение для синтаксического анализа строк, в котором исходный номер (double) преобразуется в строку и разбирается на составляющие ее компоненты. Затем он собирается по правилам в полноразмерное числовое представление. Он также учитывает языковой стандарт по запросу.

Обновление : тесты преобразований включают только однозначные целые числа, что является нормой, но алгоритм также работает для чего-то вроде: 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();
    }
}
20
ответ дан 24 November 2019 в 13:05
поделиться

Обязательное решение на основе логарифма. Обратите внимание, что это решение, поскольку оно включает в себя математические вычисления, может немного снизить точность вашего числа. Не сильно протестирован.

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');
    }
}

Редактировать: Если десятичная точка пересекает ненулевую часть числа, этот алгоритм потерпит неудачу. Я попытался сделать все просто и зашел слишком далеко.

3
ответ дан 24 November 2019 в 13:05
поделиться

Это то, что у меня есть до сих пор, похоже, работает, но, возможно, у кого-то есть лучшее решение:

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));
8
ответ дан 24 November 2019 в 13:05
поделиться
Другие вопросы по тегам:

Похожие вопросы: