Плавать на строку, используя туда и обратно

Я пытаюсь преобразовать число с плавающей точкой в ​​его строковое представление без результата, появляющегося в научной нотации.

Я впервые попробовал:

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

но это, кажется, не работает для больших значений. Например:

float largeNumber = 12345678f;
string str = largeNumber.ToString("0." + new string('#', 7));

результаты в "12345680"

Я тогда попробовал ToString("R")

это работает для большого числа выше, но если числа становятся слишком большими, это показывает их в научной нотации. Например 5000000000f результаты в "5E+09", И небольшие цифры, такие как 0.0005 результат в 0.0004999999966

Я также попытался смешать 2, но я все еще получаю научную запись в некоторых случаях.

Моя тестовая программа вставлена ​​ниже. Я ценю, что будут проблемы с точностью, но мне интересно, смогу ли я сделать что-то лучше, чем у меня?

class Program
{
    static void Main(string[] args)
    {
        Write(0.123456789f);
        Write(0.12345678f);
        Write(0.1234567f);
        Write(0.123456f);
        Write(0.12345f);
        Write(0.1234f);
        Write(0.123f);
        Write(0.12f);
        Write(0.1f);
        Write(1);
        Write(12);
        Write(123);
        Write(1234);
        Write(12345);
        Write(123456);
        Write(1234567);
        Write(12345678);
        Write(123456789);

        Console.WriteLine();

        float f = 5000000000f;
        for (int i = 0; i < 17; ++i)
        {
            Write(f);
            f /= 10;
        }

        Console.WriteLine();

        f = 5000000000f;
        for (int i = 0; i < 17; ++i)
        {
            Write(f < 1 ? f + 1 : f);
            f /= 10;
        }

        Console.Read();
    }

    static void Write(float f)
    {
        //string str = f.ToString("0." + new string('#', 7));
        //string str = f.ToString("R");
        string str = Math.Abs(f) < 1 ? f.ToString("0." + new string('#', 7)) : f.ToString("R");

        Console.WriteLine(str);
    }
}

3 ответа

Проблема в том, что float поддерживает только 7 цифр точности. Там нет никакого способа представлять 12345678f точно в float, поэтому он преобразуется в ближайшее представимое значение float, которое 12345680f, Ключевым вопросом является не размер числа, а количество цифр точности.

Также, 0.0005 не может быть представлен точно в двоичном числе с плавающей точкой; ближайшее 8-разрядное двоичное число с плавающей запятой к 0.0005 является 0.0004999999966

decimal поддерживает гораздо большую точность и может представлять числа base-10 точно с использованием стандарта N спецификатор формата.

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

largeNumber.ToString("r")

Вы можете найти список доступных форматов здесь: http://msdn.microsoft.com/en-us/library/dwhawy9k%28v=vs.110%29.aspx

0 в строке формата не для нулей, она представляет "цифру, если не ноль, и ноль, если ноль", в то время как "#" представляет "цифру, если не ноль, или ничего, если ноль".

Вы можете использовать формат f.ToString("0." + new string('#', 7)) для чисел больше нуля

Я только что проверил его в PowerShell, и он отлично работает для меня, хотя, вероятно, он использует двойные или десятичные числа:

PS C:\> $test = "{0:0.0######}"
PS C:\> $test -f 0.5
0,5
PS C:\> $test -f 0.4443423
0,4443423
PS C:\> $test -f 123.4443423
123,4443423
PS C:\> $test -f 45425123.4443423
45425123,4443423

Определенно, проблема, кажется, float точность:

PS C:\> $test -f [float]45425123.4443423
45425120,0
Другие вопросы по тегам