Наиболее эффективная / правильная практика для обрезки бессмысленных нулей в конце десятичного числа - PullRequest
0 голосов
/ 17 января 2012

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

How is a decimal which would look like 2.0100 "rightly" presented to the user as 
another "decimal" 2.01?

Я вижу много вопросов о SO, где входные данные представляют собой строку "2.0100", и мне нужно десятичное число 2.01 из них, а также вопросы, где им нужно десятичное число 2.0100, которое будет представлено в виде строки "2.01". Все это может быть достигнуто с помощью базовой строки. Трима, десятичной дроби. Разрежьте и т. Д. И вот некоторые из следующих подходов:

  1. decimal.Parse(2.0100.ToString("G29"))

  2. Использование # literal

  3. Множество строк. Параметры форматирования.

  4. Различные опции Regex

  5. Мой собственный, который я использовал до сих пор:

    if (2.0100 == 0)
        return 0;
    decimal p = decimal.Parse(2.0100.ToString().TrimEnd('0'));
    return p == 2.0100 ? p : 2.0100;
    

Но я считаю, что должен быть какой-то правильный способ сделать это в .Net (по крайней мере 4), который имеет дело с числовой операцией, а не строковой операцией. Я прошу что-то, что не имеет дело с десятичной дробью как строкой, потому что я чувствую, что это не правильный способ сделать это. Я пытаюсь узнать что-то новое. И мне бы хотелось, чтобы мои шансы увидеть увеличение производительности не менее 0,1 секунды, так как я извлекаю десятки тысяч десятичных значений из базы данных:)

Вопрос 2: Если он не присутствует в .Net, какой метод строковых значений является наиболее эффективным для получения презентабельного значения для десятичной дроби?

Редактировать: Я не просто хочу, чтобы десятичное число было представлено пользователям. В этом случае я могу использовать его как строку. Я хочу вернуть его как десятичную. Мне придется обработать эти десятичные значения позже. Таким образом, используя подход ToString, мне сначала нужно преобразовать его в строку, а затем снова разобрать в десятичную. Я ищу что-то, что не относится к классу String. Какой-то вариант преобразования десятичного числа .20100 в десятичное число .201?

Ответы [ 5 ]

2 голосов
/ 17 января 2012

«Дополнительные нули», встречающиеся в значении decimal, существуют потому, что тип System.Decimal явно хранит эти нули.Для System.Decimal, 1.23400 - это значение, отличное от 1.234, даже если численно они равны:

Коэффициент масштабирования также сохраняет любые конечные нули вДесятичное число.Конечные нули не влияют на значение десятичного числа в арифметических или сравнительных операциях.Однако конечные нули могут быть обнаружены методом ToString, если применяется соответствующая строка формата.

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

В вашем случае вы не заботитесь о них, но соответствующий ответ - не "измените десятичное число для моего конкретного приложения, чтобыон не хранит эти нули ".Вместо этого он «представляет это значение таким образом, который имеет смысл для моих пользователей».И вот для чего decimal.ToString().

1 голос
/ 18 января 2012

Хорошо, я отвечаю за себя, у меня есть решение.

return d / 1.00000000000000000000000000000m

Это просто делает это. Я также провел некоторый бенчмаркинг (время представлено как комментарии в режиме, не значит):

Метод:

    internal static double Calculate(Action act)
    {
        Stopwatch sw = new Stopwatch();

        sw.Start();
        act();
        sw.Stop();

        return sw.Elapsed.TotalSeconds;
    }

Кандидаты:

  1. return decimal.Parse(string.Format("{0:0.#############################}", d));
    //0.02ms
    
  2. return decimal.Parse(d.ToString("0.#############################"));
    //0.014ms
    
  3. if (d == 0)
        return 0;
    
    decimal p = decimal.Parse(d.ToString().TrimEnd('0').TrimEnd('.'));
    return p == d ? p : d;
    //0.016ms
    
  4. return decimal.Parse(d.ToString("G29"));
    //0.012ms
    
  5. return d / 1.00000000000000000000000000000m;
    //0.007ms
    

Нет необходимости охватывать параметры регулярных выражений. Я не хочу сказать, что производительность имеет большое значение. Я просто вытягиваю 5–20 тысяч строк одновременно. Но все же приятно знать, что существует более простая и понятная альтернатива строковому подходу.

Если вам понравился ответ, просьба перенаправить ваши голоса на здесь или здесь или здесь .

1 голос
/ 17 января 2012

Как уже отмечалось, десятичное число, в котором хранится 2.0100, может отличаться от того, в котором хранится 2.01, и это может повлиять на поведение по умолчанию ToString().

Я рекомендую никогда не использоватьthis.

Во-первых, decimal.Parse("2.0100") == decimal.Parse("2.01") возвращает true.Хотя их внутренние представления различны, это, к сожалению, IMO.Когда я использую decimal со значением 2,01, я хочу думать:

2.01

Not:

struct decimal {private int flags;личное инт привет;частный инт ло;частный int mid;/ методы, делающие это действительно полезным /}

Хотя могут существовать различные способы хранения 2.01 в приведенной выше структуре, 2,01 остается 2,01.

Если вы заботитесь оон представлен как 2.01, а не как 2.0 или 2.0100, тогда вы заботитесь о строковом представлении.Вы беспокоитесь о том, как десятичная дробь представляется в виде строки, и именно так вы должны думать об этом на этом этапе.Рассмотрим рассматриваемое правило (показаны минимальные и максимальные значащие цифры, а также следует ли включать или исключить завершающие нули) и затем код ToString, соответствующий вызову.

И сделайте это близко к месту, где используется строка.

Если вам небезразлично 2.01, то обращайтесь к нему как к десятичному знаку и рассмотрите любой код, для которого разница между 2.01 и 2.0100 имеет значение, как ошибку, и исправьте ее.

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

1 голос
/ 17 января 2012

Числа - это числа, а строки - это строки.Понятие «двойственности», представленное в английском как строчка, - 2.Понятие «двойственность», представленное как число, на самом деле не представляется возможным показать, потому что когда вы наблюдаете число, вы видите его как строку.Но ради аргумента это может быть 2 или 2.0 или 02 или 02.0 или даже 10/5.Все они являются представлениями «двойственности».

Ваша база данных на самом деле не возвращает 2.0100, то, с чем вы проверяете это значение, конвертирует его в строку и представляет его таким образом для вас.Всегда ли число имеет нули в конце, это просто предпочтение форматирования строки, всегда.

Кроме того, никогда не вызывайте Decimal.parse() в десятичной дроби, это не имеет смысла.Если вы хотите преобразовать десятичный литерал в строку, просто наберите (2.0100).ToString().TrimEnd('0')

1 голос
/ 17 января 2012

Самый простой способ отформатировать десятичное число в заданном для пользователя формате - использовать параметры форматирования decimal.ToString().

Что касается представления значения, 2.01 равно2,0100.Пока вы в пределах точности decimal, не должно иметь значения, как значение хранится в системе.Вас должно беспокоить только правильное форматирование значения для пользователя.

...