C # Double - ToString () форматирование с двумя десятичными разрядами, но без округления


153

Как мне отформатировать a Doubleв a Stringв C #, чтобы иметь только два десятичных знака?

Если я использую String.Format("{0:0.00}%", myDoubleValue)число, то округляется, и я хочу простое усечение без округления. Я также хочу, чтобы преобразование Stringбыло чувствительным к культуре.


Что вы подразумеваете под "чувствительным к культуре"? Означает ли это, что результат форматирования должен варьироваться в зависимости от ценности культуры, предоставляемой программистом? Или вы хотите использовать любую культуру по умолчанию для текущего потока?
CesarGon

Ответы:


204

Я использую следующее:

double x = Math.Truncate(myDoubleValue * 100) / 100;

Например:

Если номер 50,947563, и вы используете следующее, произойдет следующее:

- Math.Truncate(50.947563 * 100) / 100;
- Math.Truncate(5094.7563) / 100;
- 5094 / 100
- 50.94

И вот ваш ответ урезан, теперь для форматирования строки просто сделайте следующее:

string s = string.Format("{0:N2}%", x); // No fear of rounding and takes the default number format

3
-1 Вы можете выполнить форматирование с учетом культуры на том же string.Formatшаге, что и форматирование строки. Смотрите мой ответ ниже.
CesarGon

1
Замечательно. Я надеюсь, что мой комментарий теперь не выглядит так глупо. :-) Тогда я поменяю голосование вниз.
CesarGon

1
Мне это удалось, поскольку решение по форматированию строк невероятно просто, усечение было более сложным.
Кайл Розендо

1
К сожалению, ваше решение не работает, когда число меньше 1, чтобы проиллюстрировать: 0,97. Есть ли обходной путь для этой ситуации?
Али Дехган

2
@ Джонни, который не будет работать, потому что он округляет - OP хочет, чтобы это урезало (а не округлило). Разница неуловима.
BKSpurgeon

102

Следующие округляет числа, но показывает только до 2 десятичных знаков (удаляя любые завершающие нули), благодаря .##.

decimal d0 = 24.154m;
decimal d1 = 24.155m;
decimal d2 = 24.1m;
decimal d3 = 24.0m;

d0.ToString("0.##");   //24.15
d1.ToString("0.##");   //24.16 (rounded up)
d2.ToString("0.##");   //24.1  
d3.ToString("0.##");   //24

http://dobrzanski.net/2009/05/14/c-decimaltostring-and-how-to-get-rid-of-trailing-zeros/


12
Это не работает Попробуйте это с 0.2415999. Это решения округляет, а не усекает.
BJury

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

1
@mysticcoder Полагаю, мой ответ вызывает так много откликов, потому что они приходят к вопросу об операциях в поиске в Google так же, как и я, пытаясь убрать конечные нули и не обращая внимания на желание округлить вопрос об операциях. Я думаю, что я должен удалить свой ответ ...
Брайан Огден

@BrianOgden - Нет, пожалуйста, не удаляйте. Я прибыл сюда в поисках вашего ответа. +1
Роберто

35

Я предлагаю вам сначала усечь, а затем отформатировать:

double a = 123.4567;
double aTruncated = Math.Truncate(a * 100) / 100;
CultureInfo ci = new CultureInfo("de-DE");
string s = string.Format(ci, "{0:0.00}%", aTruncated);

Используйте константу 100 для усечения 2 цифр; используйте 1, а затем столько нулей, сколько цифр после десятичной точки, которую вы хотите. Используйте название культуры, которое вам нужно для настройки результата форматирования.


Я думаю, что вместо new CultureInfo("de-DE"), вы должны использовать статическое свойствоCulture.InvariantCulture
vchan


13

я использую price.ToString("0.00") для получения ведущих 0


6

Функция c #, выраженная Кайлом Розендо:

string DecimalPlaceNoRounding(double d, int decimalPlaces = 2)
{
    d = d * Math.Pow(10, decimalPlaces);
    d = Math.Truncate(d);
    d = d / Math.Pow(10, decimalPlaces);
    return string.Format("{0:N" + Math.Abs(decimalPlaces) + "}", d);
}

5

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

var d = 0.241534545765;
var result1 = d.ToString("0.###%");

var result2 = result1.Remove(result1.Length - 1);

3
Забавно, что у неработающего ответа 60 голосов (на сегодняшний день), и у этого довольно простого и пуленепробиваемого решения есть только один ...
Артур Казыханов

5
Это не будет работать в том случае, если округление влияет более чем на одну цифру над срезом. Например, 0,199999 с кодом будет иметь значение 0,20 вместо 0,19.
Бернем

4

Это работает для меня

string prouctPrice = Convert.ToDecimal(String.Format("{0:0.00}", Convert.ToDecimal(yourString))).ToString();

2

Я знаю, что это старая тема, но я просто должен был это сделать. В то время как другие подходы здесь работают, я хотел простой способ, чтобы иметь возможность влиять на множество звонков string.format. Поэтому добавление Math.Truncateко всем вызовам было не очень хорошим вариантом. Кроме того, поскольку часть форматирования хранится в базе данных, это еще больше ухудшило ситуацию.

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

string.format(new FormatProvider(), "{0:T}", 1.1299); // 1.12
string.format(new FormatProvider(), "{0:T(3)", 1.12399); // 1.123
string.format(new FormatProvider(), "{0:T(1)0,000.0", 1000.9999); // 1,000.9

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

public class FormatProvider : IFormatProvider, ICustomFormatter
{
    public object GetFormat(Type formatType)
    {
        if (formatType == typeof (ICustomFormatter))
        {
            return this;
        }
        return null;
    }

    public string Format(string format, object arg, IFormatProvider formatProvider)
    {
        if (arg == null || arg.GetType() != typeof (double))
        {
            try
            {
                return HandleOtherFormats(format, arg);
            }
            catch (FormatException e)
            {
                throw new FormatException(string.Format("The format of '{0}' is invalid.", format));
            }
        }

        if (format.StartsWith("T"))
        {
            int dp = 2;
            int idx = 1;
            if (format.Length > 1)
            {
                if (format[1] == '(')
                {
                    int closeIdx = format.IndexOf(')');
                    if (closeIdx > 0)
                    {
                        if (int.TryParse(format.Substring(2, closeIdx - 2), out dp))
                        {
                            idx = closeIdx + 1;
                        }
                    }
                    else
                    {
                        throw new FormatException(string.Format("The format of '{0}' is invalid.", format));
                    }
                }
            }
            double mult = Math.Pow(10, dp);
            arg = Math.Truncate((double)arg * mult) / mult;
            format = format.Substring(idx);
        }

        try
        {
            return HandleOtherFormats(format, arg);
        }
        catch (FormatException e)
        {
            throw new FormatException(string.Format("The format of '{0}' is invalid.", format));
        }
    }

    private string HandleOtherFormats(string format, object arg)
    {
        if (arg is IFormattable)
        {
            return ((IFormattable) arg).ToString(format, CultureInfo.CurrentCulture);
        }
        return arg != null ? arg.ToString() : String.Empty;
    }
}

2

У меня была эта проблема с формами Xamarin и я решил ее следующим образом:

percent.ToString("0.##"+"%")

1

Для чего стоит, для показа валюты, вы можете использовать "C":

double cost = 1.99;
m_CostText.text = cost.ToString("C"); /*C: format as currentcy */

Вывод: $1.99


0

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

.NET Framework также поддерживает пользовательское форматирование. Обычно это включает в себя создание класса форматирования, который реализует как IFormatProvider, так и ICustomFormatter . (MSDN)

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

В CodeProject есть статья о том, как реализовать свой собственный IFormatProvider / ICustomFormatter . В этом случае «расширение» существующего числового формата может быть лучшим выбором. Это не выглядит слишком сложно.


0

Следующее может использоваться только для отображения, которое использует свойство String.

double value = 123.456789;
String.Format("{0:0.00}", value);

Это даст «123,46». Вопрос конкретно не требует округления.
Тобберот

0

Решение:

var d = 0.123345678; 
var stringD = d.ToString(); 
int indexOfP = stringD.IndexOf("."); 
var result = stringD.Remove((indexOfP+1)+2);

(indexOfP + 1) +2 (это число зависит от того, сколько номеров вы хотите сохранить. Я даю два, потому что хочет владелец вопроса.)


0

Также обратите внимание на информацию о культуре вашей системы. Здесь мое решение без округления.

В этом примере вам просто нужно определить переменную MyValue как double. В результате вы получите отформатированное значение в строковой переменной NewValue .

Примечание. Также установите оператор C # using:

using System.Globalization;  

string MyFormat = "0";
if (MyValue.ToString (CultureInfo.InvariantCulture).Contains (CultureInfo.InvariantCulture.NumberFormat.NumberDecimalSeparator))
   {
      MyFormat += ".00";
   }

string NewValue = MyValue.ToString(MyFormat);
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.