Как округлить десятичное значение до 2 десятичных знаков (для вывода на страницу)

460

При отображении значения десятичной дроби в настоящее время с .ToString(), оно точно похоже на 15 знаков после запятой, и поскольку я использую его для представления долларов и центов, я хочу, чтобы результат был равен 2 десятичным знакам.

Использую ли для этого вариант .ToString()?

Теги:
decimal
rounding

15 ответов

674
Лучший ответ
decimalVar.ToString ("#.##"); // returns "" when decimalVar == 0

или

decimalVar.ToString ("0.##"); // returns "0"  when decimalVar == 0
  • 29
    проблема здесь, когда у нас есть 0,00; он возвращает пустую строку.
  • 158
    Тогда вы можете сделать decimalVar.ToString ("0. ##"). Вы также можете использовать 0,00 в качестве строки форматирования.
Показать ещё 11 комментариев
440

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

  • Не использовал округление банкиров
  • Не сохранял значение как десятичное.

Это то, что я бы использовал:

decimal.Round(yourValue, 2, MidpointRounding.AwayFromZero);

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

  • 29
    О округлении банкира : xbeat.net/vbspeed/i_BankersRounding.htm
  • 3
    ToString или string.Format не используют округление банкиров: msdn.microsoft.com/en-us/library/0c899ak8.aspx#sectionToggle1
Показать ещё 2 комментария
245
decimalVar.ToString("F");

Это будет:

Завершить до 2 знаков после запятой, например. 23.456 = > 23.46

Убедитесь, что всегда есть 2 десятичных разряда, например. 23 = > 23,00, 12,5 = > 12,50

Идеально подходит для валюты и отображения денежных сумм.

  • 9
    Это прекрасно работает, когда имеет только 1 десятичный знак; .ToString ("#. ##") завершается ошибкой. Этот ответ намного лучше
  • 2
    Не будет ли округлять 23,456 => 23,46?
Показать ещё 4 комментария
85

Если вам просто нужно это для отображения, используйте string.Format

String.Format("{0:0.00}", 123.4567m);      // "123.46"

http://www.csharp-examples.net/string-format-double/

"m" - десятичный суффикс. О десятичном суффиксе:

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

  • 10
    Технически, для десятичной точки это было бы 123,4567 м, да? Без суффикса "м", это двойной
  • 0
    или ярлык $ "{value: 0.00}"
47

Учитывая decimal d = 12.345; выражения d.ToString( "C" ) или String.Format( "{0: C}", d ) yield $12,35 - обратите внимание, что используются текущие настройки валюты культуры, включая символ.

Обратите внимание, что "C" использует количество цифр из текущей культуры. Вы всегда можете переопределить значение по умолчанию для принудительной точности с помощью C{Precision specifier}, как String.Format("{0:C2}", 5.123d).

  • 6
    Только правильный ответ, если вы хотите знак доллара.
  • 4
    @ Slick86 - актуальный знак
34

Если вы хотите, чтобы он был отформатирован запятыми, а также десятичной точкой (но не символом валюты), например, 3 456 789,12...

decimalVar.ToString("n2");
  • 1
    Лучше ответить, так как вопрос был о выводе на страницу, а форматирование чисел важно для больших чисел. Кроме того, «n *» учитывает текущую культуру, поэтому это могут быть «3.456.789,12», «3 456 789,12» и т. Д.
23

Уже есть два ответа с высоким рейтингом, которые относятся к Decimal.Round(...), но я думаю, что требуется немного больше объяснений - потому что существует неочевидное неожиданное важное свойство Decimal.

Десятичный "знает", сколько десятичных знаков оно основано на том, откуда оно было.

Например, следующее может быть неожиданным:

Decimal.Parse("25").ToString()          =>   "25"
Decimal.Parse("25.").ToString()         =>   "25"
Decimal.Parse("25.0").ToString()        =>   "25.0"
Decimal.Parse("25.0000").ToString()     =>   "25.0000"

25m.ToString()                          =>   "25"
25.000m.ToString()                      =>   "25.000"

Выполнение тех же операций с Double не даст десятичных знаков ("25") для каждого из указанных выше.

Если вы хотите десятичное число до двух знаков после запятой, это примерно на 95% шанс, потому что это валюта, и в этом случае это, вероятно, отлично в течение 95% времени:

Decimal.Parse("25.0").ToString("c")     =>   "$25.00"

Или в XAML вы просто используете {Binding Price, StringFormat=c}

В одном случае я столкнулся с тем, где мне понадобилось десятичное AS, когда десятичное число было при отправке XML в веб-службу Amazon. Служба жаловалась, потому что значение Decimal (первоначально из SQL Server) отправлялось как 25.1200 и отклонено, (25.12 - ожидаемый формат).

Все, что мне нужно было сделать, это Decimal.Round(...) с двумя десятичными знаками, чтобы устранить проблему.

 // This is an XML message - with generated code by XSD.exe
 StandardPrice = new OverrideCurrencyAmount()
 {
       TypedValue = Decimal.Round(product.StandardPrice, 2),
       currency = "USD"
 }

TypedValue имеет тип Decimal, поэтому я не мог просто сделать ToString("N2") и должен был округлить его и сохранить его как Decimal.

  • 5
    +1 это отличный ответ. Когда вы говорите, что System.Decimal «знает, сколько десятичных разрядов имеет», - это означает, что System.Decimal не является самонормализующимся, как другие типы с плавающей запятой. Другое полезное свойство System.Decimal заключается в том, что результат математических операций всегда имеет наибольшее количество десятичных разрядов из входных аргументов, т.е. 1,0 м + 2 000 м = 3 000 м . Вы можете использовать этот факт для преобразования десятичного знака без десятичных знаков в 2 десятичных знака, просто умножив его на 1,00 м, например. 10м * 1,00м = 10,00м .
  • 2
    MattDavey's неправильный, десятичная точность добавлена. (1,0м * 1,00м) .ToString () = "1000"
Показать ещё 1 комментарий
17

Вот небольшая программа Linqpad для отображения разных форматов:

void Main()
{
    FormatDecimal(2345.94742M);
    FormatDecimal(43M);
    FormatDecimal(0M);
    FormatDecimal(0.007M);
}

public void FormatDecimal(decimal val)
{
    Console.WriteLine("ToString: {0}", val);
    Console.WriteLine("c: {0:c}", val);
    Console.WriteLine("0.00: {0:0.00}", val);
    Console.WriteLine("0.##: {0:0.##}", val);
    Console.WriteLine("===================");
}

Вот результаты:

ToString: 2345.94742
c: $2,345.95
0.00: 2345.95
0.##: 2345.95
===================
ToString: 43
c: $43.00
0.00: 43.00
0.##: 43
===================
ToString: 0
c: $0.00
0.00: 0.00
0.##: 0
===================
ToString: 0.007
c: $0.01
0.00: 0.01
0.##: 0.01
===================
13
  • 0
    разве это не использует банковское округление?
  • 0
    Это лучший способ, потому что значение не преобразуется в строку, и вы все равно можете выполнять математические операции
Показать ещё 1 комментарий
8

Ни один из них не сделал именно то, что мне нужно, чтобы заставить 2 d.p. и округлить как 0.005 -> 0.01

Принуждение 2 ч. требует увеличения точности на 2 д.п. для обеспечения того, чтобы у нас было не менее 2 d.p.

затем округляем, чтобы гарантировать, что у нас не более 2 d.p.

Math.Round(exactResult * 1.00m, 2, MidpointRounding.AwayFromZero)

6.665m.ToString() -> "6.67"

6.6m.ToString() -> "6.60"
6

Вы можете использовать system.globalization для форматирования номера в любом требуемом формате.

Например:

system.globalization.cultureinfo ci = new system.globalization.cultureinfo("en-ca");

Если у вас есть decimal d = 1.2300000, и вам нужно обрезать его до двух знаков после запятой, тогда его можно напечатать следующим образом: d.Tostring("F2",ci);, где F2 имеет строковое обозначение до двух знаков после запятой, а ci - это locale или cultureinfo.

для получения дополнительной информации проверьте эту ссылку
http://msdn.microsoft.com/en-us/library/dwhawy9k.aspx

  • 0
    +1, но - объект CultureInfo будет влиять только на символ Юникода, используемый для обозначения десятичного знака. например. FR-FR будет использовать запятую вместо точки. Это не связано с количеством отображаемых десятичных знаков.
3

Самый верный ответ описывает метод форматирования строкового представления десятичного значения, и он работает.

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

public static class PrecisionHelper
{
    public static decimal TwoDecimalPlaces(this decimal value)
    {
        // These first lines eliminate all digits past two places.
        var timesHundred = (int) (value * 100);
        var removeZeroes = timesHundred / 100m;

        // In this implementation, I don't want to alter the underlying
        // value.  As such, if it needs greater precision to stay unaltered,
        // I return it.
        if (removeZeroes != value)
            return value;

        // Addition and subtraction can reliably change precision.  
        // For two decimal values A and B, (A + B) will have at least as 
        // many digits past the decimal point as A or B.
        return removeZeroes + 0.01m - 0.01m;
    }
}

Пример unit test:

[Test]
public void PrecisionExampleUnitTest()
{
    decimal a = 500m;
    decimal b = 99.99m;
    decimal c = 123.4m;
    decimal d = 10101.1000000m;
    decimal e = 908.7650m

    Assert.That(a.TwoDecimalPlaces().ToString(CultureInfo.InvariantCulture),
        Is.EqualTo("500.00"));

    Assert.That(b.TwoDecimalPlaces().ToString(CultureInfo.InvariantCulture),
        Is.EqualTo("99.99"));

    Assert.That(c.TwoDecimalPlaces().ToString(CultureInfo.InvariantCulture),
        Is.EqualTo("123.40"));

    Assert.That(d.TwoDecimalPlaces().ToString(CultureInfo.InvariantCulture),
        Is.EqualTo("10101.10"));

    // In this particular implementation, values that can't be expressed in
    // two decimal places are unaltered, so this remains as-is.
    Assert.That(e.TwoDecimalPlaces().ToString(CultureInfo.InvariantCulture),
        Is.EqualTo("908.7650"));
}
  • 0
    Это единственный верный ответ на вопрос
  • 0
    Также очень полезно, спасибо!
2

Ответ Майка М. был идеальным для меня на .NET, но .NET Core не имеет метода decimal.Round на момент написания.

В .NET Core мне пришлось использовать:

decimal roundedValue = Math.Round(rawNumber, 2, MidpointRounding.AwayFromZero);

Хакерным методом, включая преобразование в строку, является:

public string FormatTo2Dp(decimal myNumber)
{
    // Use schoolboy rounding, not bankers.
    myNumber = Math.Round(myNumber, 2, MidpointRounding.AwayFromZero);

    return string.Format("{0:0.00}", myNumber);
}
2

https://msdn.microsoft.com/en-us/library/dwhawy9k%28v=vs.110%29.aspx

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

double whateverYouWantToChange = whateverYouWantToChange.ToString("F2");

если вы хотите это для валюты, вы можете сделать это проще, набрав "C2" вместо "F2"

0

Очень редко вам нужна пустая строка, если значение равно 0.

decimal test = 5.00;
test.ToString("0.00");  //"5.00"
decimal? test2 = 5.05;
test2.ToString("0.00");  //"5.05"
decimal? test3 = 0;
test3.ToString("0.00");  //"0.00"

Самый рейтинговый ответ неверен и потерял 10 минут (большинства) людей.

  • 1
    в основном "#" означает цифру числа (если необходимо) (без дополнения, если не нужно) "0" означает цифру числа (не важно, что) (дополнено нулями, если не доступно)

Ещё вопросы

Сообщество Overcoder
Наверх
Меню