Перетворення вдвічі в рядок без наукових позначень


81

Як перетворити подвійне в подання рядка з плаваючою крапкою без наукових позначень у .NET Framework?

"Маленькі" зразки (ефективні цифри можуть бути будь-якого розміру, наприклад 1.5E200або 1e-200):

3248971234698200000000000000000000000000000000
0.00000000000000000000000000000000000023897356978234562

Жоден із стандартних форматів чисел не є таким, і власний формат також, здається, не дозволяє мати відкриту кількість цифр після десяткового роздільника.

Це не дублікат того, як перетворити double у рядок без подання степеня 10 (E-05), оскільки відповіді, подані там, не вирішують суть проблеми. Прийнятим рішенням у цьому питанні було використання фіксованої точки (наприклад, 20 цифр), що я не хочу. Форматування фіксованої точки та обрізання зайвого 0 також не вирішує проблему, оскільки максимальна ширина для фіксованої ширини становить 99 символів.

Примітка: рішення має правильно працювати з користувацькими форматами чисел (наприклад, інший десятковий роздільник, залежно від інформації про культуру).

Редагувати: Питання насправді стосується лише витіснення вищезазначених цифр. Мені відомо про те, як працюють числа з плаваючою комою, і які числа можна використовувати і обчислювати з ними.


1
у вас є рішення цього питання зараз?
Кіра

@Anand, є два рішення, які працюють (Пол Сасік і мій), навіть якщо вони не надто "приємні" (проходять через маніпуляції рядками).
Lucero

Відповіді:


41

Для загального рішення¹ потрібно зберегти 339 місць:

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

Максимальна кількість ненульових десяткових цифр - 16. 15 знаходиться праворуч від десяткової коми. Показник може перемістити ці 15 цифр максимум на 324 місця вправо. ( Див. Діапазон і точність. )

Він працює double.Epsilon, double.MinValue, double.MaxValueі нічого між ними.

Продуктивність буде набагато більшою, ніж рішення для маніпулювання регулярними виразами / рядками, оскільки вся робота з форматуванням та рядками виконується за один прохід некерованим кодом CLR. Крім того, набагато простіше довести правильність коду.

Для зручності використання та ще кращої продуктивності зробіть це постійним:

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

¹ Оновлення: Я помилково сказав, що це також рішення без втрат. Насправді це не так, оскільки ToStringйого нормальне округлення відображається для всіх форматів, крім r. Живий приклад. Дякую, @Loathing! Будь ласка, перегляньте відповідь Лотінга, якщо вам потрібна можливість зворотнього перельоту у позначеннях із фіксованою точкою (тобто, якщо ви використовуєте .ToString("r")сьогодні).


Хороший і досить короткий, але якщо вам не потрібні надзвичайно великі значення, ви можете зробити це в 10 разів швидше. Дивіться моя відповідь: stackoverflow.com/a/36204442/143684
ygoe

Дякую, працювали чудово. Ти чудова людина. Прихильний.
Снуп

1
Це рішення не є "без втрат". Приклад: String t1 = (0.0001/7).ToString("0." + new string('#', 339)); // 0.0000142857142857143проти: String t2 = (0.0001/7).ToString("r"); // 1.4285714285714287E-05Точність втрачається в кінці десяткових знаків.
Ненависть

30

У мене була подібна проблема, і це спрацювало для мене:

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

F99 може бути надмірним, але ви розумієте.


1
99 недостатньо, і він повинен працювати як до, так і після коми.
Lucero

2
TrimEnd('0')достатньо, оскільки charмасив є params. Тобто будь-які chars, що передаються, TrimEndбудуть автоматично згруповані в масив.
Grault

99 це НЕ досить для вирішення загального призначення. doubleValue.ToString("0." + new string('#', 339))без втрат. Порівняйте ці методи, використовуючи значення double.Epsilon.
jnm2

20

Це рішення синтаксичного аналізу рядків, де вихідний номер (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();
    }
}

Га Чесно кажучи, я помітив, що його проголосували проти, тому я не дуже уважно вивчав код. я прочитав це щойно, і ти маєш рацію. Вони близькі, я просто вирішив не використовувати RegEx у своєму процесі та зробив власний синтаксичний розбір рядків. Ви тестували це рішення? Це повний консольний додаток.
Пол Сасік

Поки що, скоро це зроблю ...;)
Lucero

3
Це легше читати, оскільки вам не потрібно переглядати регулярний вираз.
Грегорі

+1 LOL @ "grok the regex" мені це подобається. я зроблю це частиною мого просторового розвитку! Дякую.
Пол Сасік

Ну, у Regex принаймні є красиво названі групи замість неспецифічних індексів у деяких масивах ...;)
Lucero

13

Ви можете кастовать doubleдо , decimalа потім зробити ToString().

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

Я не робив тестування продуктивності, яке було швидшим, перекидання з 64-розрядних doubleна 128-розрядні decimalчи рядок формату понад 300 символів. О, і можуть бути помилки переповнення під час перетворення, але якщо ваші значення відповідають a, decimalце має спрацювати нормально.

Оновлення: Кастинг, здається, набагато швидший. Використовуючи підготовлений рядок форматування, як зазначено в іншій відповіді, форматування мільйона разів займає 2,3 секунди, а трансляція лише 0,19 секунди. Повторюваний. Це в 10 разів швидше . Зараз мова йде лише про діапазон значень.


На жаль, це не працює для даної специфікації дуже великих чи малих чисел. ((decimal)(1e-200)).ToString()наприклад, повертається, 0що є неправильним.
Lucero

1
Щоб бути справедливим і порівняти яблука з яблуками, вам слід порівняти цей метод double.ToString("0.############################"). Згідно з моїм тестом, ваш лише в 3 рази швидший. У будь-якому випадку, це вірна відповідь лише у тому випадку, якщо ви точно знаєте, що вам не потрібно друкувати цифри внизу 1e-28і що ваш подвійний розмір не великий, обидва з яких не є обмеженнями у вихідному питанні.
jnm2

2
Це досить гарне рішення, враховуючи те, що ви знаєте діапазон значень
Артур Удод

8

Це те, що я маю на даний момент, здається, працює, але, можливо, хтось має краще рішення:

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

-1, оскільки не забезпечує рішення для наступної обстановки (і не може): подвійний d1 = 1e-200; d = d + 1; ToFloatingPointString (d) тут просто повертає 1. Не 1000 ........... 000001.
JCasso

5
Додавання одного до дуже маленького подвійного - це лише ваша ідея, і воно не має нічого спільного з актуальним питанням. Якщо ви просто запустите його без d = d + 1, ви побачите, що він насправді відображає 0.000 ..... 0001.
Lucero

Знайдіть спосіб обчислити 1e-200 під час виконання замість того, щоб встановлювати "постійне" значення, я проголосую його.
JCasso

2
Нема проблем. double x = 1.0; for (int i = 0; i < 200; i++) x /= 10; Console.WriteLine(x);
Lucero

6
Це тому, що насправді значущими є лише 15 цифр, але ви можете «перекласти» їх за допомогою показника ступеня, щоб він був дуже великим або дуже маленьким. Але ви не можете додати дуже маленьке число з числом, яке більше, ніж приблизно на 15 цифр, оскільки це перевищує кількість значущих цифр, і оскільки більша кількість є більш значною, мала частина буде втрачена. Тому обчислення з числами у подібному діапазоні (наприклад, додавання 1e-200 та 1e-200, або 1 + 1, або 1e200 + 1e200) справді працює, але змішування таких значень призведе до округлення меншого значення.
Lucero

4

Проблема використання #.###...###або F99полягає в тому, що він не зберігає точності в кінці десяткових знаків, наприклад:

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

Проблема в DecimalConverter.csтому, що це повільно. Цей код - така сама ідея, як відповідь Сасика, але вдвічі швидша. Метод одиничного випробування внизу.

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

3

Обов’язкове рішення на основі логарифму. Зауважте, що це рішення, оскільки воно передбачає математику, може трохи знизити точність вашого числа. Не сильно перевірений.

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

Редагувати: якщо десяткова точка перетинає ненульову частину числа, цей алгоритм зазнає невдач. Я пробував просте і зайшов занадто далеко.


Дякуємо за внесок, я спробую реалізувати повністю робоче рішення, подібне до цього, і порівняти його з моїм.
Lucero

3

У старі часи, коли нам доводилося писати власні форматори, ми виділяли мантису та експоненту та форматували їх окремо.

У цій статті Джона Скіта ( https://csharpindepth.com/articles/FloatingPoint ) він надає посилання на свою процедуру DoubleConverter.cs, яка повинна робити саме те, що ви хочете. Скіт також посилається на це при вилученні мантиси та експоненти з подвійного в c # .


Дякую за посилання, я вже пробував код від Jon, однак для моєї мети він виглядає занадто точним; наприклад, 0,1 не відображається як 0,1 (що технічно правильно, але не те, що мені потрібно) ...
Lucero

Так, але ти бачиш, вся суть коду Джона полягає у тому, щоб ВІДКРИТИ номер, і це для мого випадку занадто багато. Округлення, як це було зроблено під час виконання ToString (), для мене просто добре, і, мабуть, це також те, чому більшість запропонованих тут рішень використовують ToString () як основу для подальшої обробки.
Lucero

Привіт! Я приїжджав сюди з 10 років у майбутньому, щоб повідомити вам, що гіперпосилання на статтю Джона порушено.
Нік Ваккаро,

2

Я щойно імпровізував код вище, щоб він працював для від’ємних експоненціальних значень.

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

Цей код бере вхідний каталог і на основі роздільника перетворює всі значення в наукових позначеннях у числовий формат.

Дякую


1

спробуйте це:

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

0

Будучи мільйонами програмістів у всьому світі, це завжди гарна практика - спробувати здійснити пошук, якщо хтось уже натрапив на вашу проблему. Іноді рішення є сміття, а це означає, що настав час написати власне, а іноді є і чудові, наприклад, такі:

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

(докладніше: http://www.yoda.arachsys.com/csharp/floatingpoint.html )


1
Це те саме, що вже розміщено ebpower, дивіться коментарі там ...;)
Lucero

0
string strdScaleFactor = dScaleFactor.ToString(); // where dScaleFactor = 3.531467E-05

decimal decimalScaleFactor = Decimal.Parse(strdScaleFactor, System.Globalization.NumberStyles.Float);

Не могли б ви коротко пояснити, що робить цей код і чим він відрізняється від інших 15-ти відповідей?
JJJ

Ласкаво просимо до Stack Overflow! Незважаючи на те, що цей фрагмент коду може вирішити питання, включення пояснення дійсно допомагає поліпшити якість вашої публікації. Пам’ятайте, що ви будете відповідати на запитання для читачів у майбутньому, і ці люди можуть не знати причин вашої пропозиції коду. Будь ласка, також намагайтеся не переповнювати свій код пояснювальними коментарями, це зменшує читабельність як коду, так і пояснень!
kayess

-1

Я можу помилятися, але хіба це не так?

data.ToString("n");

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


Побачивши вашу відповідь, я, мабуть, неправильно зрозумів ваше запитання, вибачте.
csharptest.net

Ні, по-перше, я не хочу роздільника тисяч, а по-друге, здається, після коми завжди є фіксована кількість цифр. Див. Також довідку MSDN щодо формату N: msdn.microsoft.com/en-us/library/dwhawy9k.aspx#NFormatString
Lucero,

Ви також можете додати більше після десяткової коми (тобто "n8", або "n50" тощо).
BrainSlugs83,

-1

Просто щоб спиратися на те, що сказав jcasso, що ви можете зробити, це відрегулювати своє подвійне значення, змінивши показник ступеня, щоб ваш улюблений формат зробив це за вас, застосував формат, а потім заповнив результат нулями для компенсації коригування.


Показник в числах із плаваючою комою IEEE є 2-базовим, але десяткові числа - 10-базисними. Тому це просто не працює. Це також причина, чому ви не можете зберегти 0,1 як точне значення в дублі. Або просто надайте зразок (код), якщо ви вважаєте, що я неправильно зрозумів вашу відповідь.
Люсеро

-1

я думаю, вам потрібно використовувати лише IFormat з

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

приклад:

double d = double.MaxValue;
string s = d.ToString(d, System.Globalization.NumberStyles.Number);

6
Це навіть не компілюється, чи можете ви розмістити щось, що компілюється?
Lucero

-1

Моє рішення було використовувати власні формати. спробуйте це:

double d;
d = 1234.12341234;
d.ToString("#########0.#########");

2
Спробуйте скористатися тестовими номерами, які я вказав вище: d = 1.5E200і d = 1E-200. Отриманий рядок повинен містити майже 200 0символів, або ваше рішення не працює.
Lucero

9 десяткових знаків недостатньо для загального рішення. doubleValue.ToString("0." + new string('#', 339))без втрат. Порівняйте ці методи, використовуючи значення double.Epsilon.
jnm2

-1

Для мене це чудово працює ...

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

//Output: "150000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"

1
Так, це працює для великої кількості, але ні для чого, що стоїть за комою, особливо не для чогось подібного 1.5e-200.
Lucero
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.