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

649

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

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

ошеломляет
источник

Ответы:

912
decimalVar.ToString ("#.##"); // returns "" when decimalVar == 0

или

decimalVar.ToString ("0.##"); // returns "0"  when decimalVar == 0
albertein
источник
31
проблема здесь, когда у нас есть 0,00; он возвращает пустую строку.
Джронни
164
Тогда вы можете сделать decimalVar.ToString ("0. ##"). Вы также можете использовать 0,00 в качестве строки форматирования.
Альбертейн
54
С этим решением вы не получите форматирование культуры, которое можно ожидать при чтении чисел. Для этого вы должны использовать ToString ("N2") или ToString ("N").
Shautieh
2
Метод @Hill Decimalи Doubletype ToStringпринимает аргумент для форматирования. Попробуйте сначала преобразовать ваше значение в десятичное / двойное.
Сохаиби
1
@ f470071 Десятичные дроби являются типами значений и поэтому никогда не «модифицируются». Независимо от того, ToString () никогда не ожидал изменить содержимое того, что он вызывается.
Джастин Скилз
590

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

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

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

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

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

Майк М.
источник
3
ToString или string.Format не используют округление банкиров: msdn.microsoft.com/en-us/library/0c899ak8.aspx#sectionToggle1
Matthijs Wessels
1
@MatthijsWessels, я знаю ... но он не сохраняет значение в десятичном виде.
Майк М.
1
Это лучший способ по-настоящему представить два десятичных знака, так как он не пропускает конечные нули.
LiquidDrummer
355
decimalVar.ToString("F");

Это будет:

  • Округлить до 2 десятичных знаков, например. 23.45623.46
  • Убедитесь, что всегда есть 2 десятичных знака, например. 2323.00; 12.512.50

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

Ознакомьтесь с документацией по ToString ("F") (спасибо Джону Шнайдеру).

Sofox
источник
10
Это прекрасно работает, когда имеет только 1 десятичный знак; .ToString ("#. ##") завершается ошибкой. Этот ответ намного лучше
Эрик Фрик
2
Не будет ли округлять 23,456 => 23,46?
rtpHarry
14
Документация о том, что здесь означает «F» и как она работает: msdn.microsoft.com/en-us/library/…
Джон Шнайдер
4
Почему бы .ToString ("N") вместо "F"? Насколько я понимаю, они оба будут работать для нужд этого вопроса, но N также поставит запятые для чисел в тысячах.
jgerman
Примечание: .может быть заменено на ,основе культуры. Вы должны указать CultureInfo.InvariantCultureвторой аргумент, чтобы отключить это.
Дункан Лук
106

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

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м, да? Без суффикса "m" это двойное число
Адам Теген
2
или ярлык $ "{value: 0.00}"
mamczas
56

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

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

Hafthor
источник
4
@ Slick86 - современный знак
fubo
48

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

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

Уже есть два ответа с высокими оценками, которые относятся к 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}

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

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

 // 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.

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

Вот небольшая программа 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
===================
Что бы круто
источник
16

Math.Round Метод (Десятичный, Int32)

Джон Смит
источник
разве это не использует банковское округление?
Данимал
Это лучший способ, потому что значение не преобразуется в строку, и вы все еще можете выполнять математические операции
shinji14
@Danimal: Вы можете предоставить третий аргумент для изменения типа округления
Джей Салливан
11

Очень редко вы захотите пустую строку, если значение равно 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 минут времени (большинства) людей.

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

Ответ Майка М. был идеален для меня в .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);
}
HockeyJ
источник
9

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

Форсирование 2 дп требует повышения точности на 2 дп, чтобы обеспечить как минимум 2 дп

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

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

6.665m.ToString() -> "6.67"

6.6m.ToString() -> "6.60"
Кайдо
источник
9

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

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

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;
    }
}

Пример юнит-теста:

[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"));
}
Alex
источник
7

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

Например:

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

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

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

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

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

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

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

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

Джефф Хосе
источник
1
Double Amount = 0;
string amount;
amount=string.Format("{0:F2}", Decimal.Parse(Amount.ToString()));
JIYAUL MUSTAPHA
источник
1

Если вам нужно сохранить только 2 десятичных знака (то есть обрезать все остальные десятичные цифры):

decimal val = 3.14789m;
decimal result = Math.Floor(val * 100) / 100; // result = 3.14

Если вам нужно сохранить только 3 знака после запятой:

decimal val = 3.14789m;
decimal result = Math.Floor(val * 1000) / 1000; // result = 3.147
Алексей Мялкин
источник