Парсим string to float без экспоненты в C#

Ситуация простейшая, но именно на ней я застрял. Есть следующий метод, конвертирующий строку в float?

public static float? ToSingleNullable(string value)
{
    if (string.IsNullOrEmpty(value))
        return null;
    else
    {
        float number = 0;
        if (float.TryParse(value, out number))
            return number;
        return null;
    }
}

В ситуации, когда на входе приходит что-то больше 19 999 999, то float.TryParse вместо, скажем, 20 000 012 выводит 2e+6 или где-то там. При обратной конвертации в лучшем случае получаю 20 000 010. Причём предсказать, что получится - 20 000 000 или 20 000 010 не могу.

В общем, как сделать так, чтобы вот текущий метод возвращал число с плавающей точкой именно в десятичной записи?

В сети куча примеров для .ToString(), а вот с обратной конвертацией пусто. Сменить на decimal не выйдет - метод должен вернуть именно float.

Строку вводит пользователь в человеческом виде. То есть грубо говоря получается такое:

string str = "20100999";
float number = ToSingleNullable(str);
Console.WriteLine(number);//условно 2е+6

Ответы (1 шт):

Автор решения: Alexander Petrov

Для начала, упростим ваш метод до следующего:

public static float? ToSingleNullable(string value)
{
    if (float.TryParse(value, out float number))
        return number;
    return null;
}

Теперь немного теории.

Вещественные числа имеют некоторую точность. Она не может быть бесконечной, потому что тогда потребуется бесконечное количество памяти для хранения одного числа. Соответственно, неизбежно часть данных теряется.

float f = 20100999;
Console.WriteLine(f); // 2,0101E+07
Console.WriteLine(f.ToString("F0")); // 20101000

Из этого примера следует, что значение 20100999 невозможно точно представить в виде вещественного числа одинарной точности.

Следовательно, если вы хотите получить представление числа в определённом виде, то нужно задать желаемый формат: Standard numeric format strings, Custom numeric format strings.

Я использовал формат F с указанием спецификатора точности: 0 десятичных знаков.

string str = "20100999";
float? number = ToSingleNullable(str);
Console.WriteLine(number.Value.ToString("F0")); // 20101000

Дополню. У числа в двоичном виде нет никакого формата. Это просто набор нолей и единиц.

float f = 20100999;
var bytes = BitConverter.GetBytes(f);

foreach (byte b in bytes)
    Console.Write(Convert.ToString(b, 2) + " ");
Console.WriteLine();

Результат:

11000100 1011011 10011001 1001011

Это и есть искомое число в памяти компьютера. А экспоненциальная форма она только для нас, для людей. Мы можем эти биты вывести в разных удобных для нас представлениях.

→ Ссылка