C # Double - formatowanie ToString () z dwoma miejscami dziesiętnymi, ale bez zaokrąglania

153

Jak sformatować a Doubledo a Stringw C #, aby mieć tylko dwa miejsca po przecinku?

Jeśli użyję String.Format("{0:0.00}%", myDoubleValue)liczby, jest ona zaokrąglana i chcę prostego obcięcia bez zaokrąglania. Chcę również, aby konwersja Stringbyła wrażliwa na kulturę.

kjv
źródło
Co masz na myśli mówiąc „wrażliwy kulturowo”? Czy to oznacza, że ​​wynik formatowania musi się różnić w zależności od wartości kultury dostarczonej przez programistę? Czy chcesz użyć dowolnej kultury, która jest domyślna dla bieżącego wątku?
CesarGon

Odpowiedzi:

204

Używam następujących:

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

Na przykład:

Jeśli numer to 50.947563 i użyjesz tego, wydarzy się co następuje:

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

Twoja odpowiedź została obcięta, teraz, aby sformatować ciąg, wykonaj następujące czynności:

string s = string.Format("{0:N2}%", x); // No fear of rounding and takes the default number format
Kyle Rosendo
źródło
3
-1 Formatowanie uwzględniające kulturę można wykonać w tym samym string.Formatkroku, który formatuje ciąg. Zobacz moją odpowiedź poniżej.
CesarGon
1
To wspaniale. Mam nadzieję, że mój komentarz nie wygląda teraz tak głupio. :-) W takim razie zmienię mój głos przeciw.
CesarGon
1
Dla mnie tak było, ponieważ rozwiązanie dotyczące formatowania napisów jest niewiarygodnie proste, obcięcie było trudniejsze.
Kyle Rosendo
1
Niestety, twoje rozwiązanie nie działa, gdy liczba jest mniejsza niż 1, co ilustruje: 0,97, czy jest jakieś obejście tej sytuacji?
Ali Dehghan
2
@Jonny, który nie zadziała, ponieważ zaokrągla - OP chce, aby został obcięty (a nie zaokrąglony). Różnica jest subtelna.
BKSpurgeon
102

Następujące zaokrągla liczby, ale pokazuje tylko do 2 miejsc po przecinku (usuwając wszelkie końcowe zera), dzięki .##.

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/

Brian Ogden
źródło
12
To nie działa. Wypróbuj z 0.2415999. To rozwiązanie zaokrągla, a nie obcina.
BJury
5
Wow, tyle głosów w górę, a mimo to używa zaokrąglania. Może być konieczne wskazanie, że zaokrąglanie zmierza w kierunku najbliższego żądanego miejsca po przecinku, podczas gdy obcięcie jest ucinaniem po najbliższym żądanym miejscu dziesiętnym.
mysticcoder
1
@mysticcoder Wydaje mi się, że moja odpowiedź zyskuje tak wiele głosów pozytywnych, ponieważ przychodzą do pytania ops w wyszukiwarce Google w taki sam sposób, jak ja, próbując usunąć końcowe zera i nie szukając zaokrąglenia w pytaniu dotyczącym operacji. Chyba powinienem usunąć swoją odpowiedź ...
Brian Ogden
@BrianOgden - Nie, proszę nie usuwać. Przyjechałem tutaj, szukając twojej odpowiedzi. +1
Roberto
35

Proponuję najpierw obciąć, a następnie sformatować:

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

Użyj stałej 100 dla obcinania 2 cyfr; użyj 1, po którym następuje tyle zer, ile cyfr po przecinku chcesz. Użyj nazwy kultury, której potrzebujesz, aby dostosować wynik formatowania.

CesarGon
źródło
Myślę, że zamiast tego new CultureInfo("de-DE")powinieneś użyć właściwości statycznejCulture.InvariantCulture
vchan
15

Najprostsza metoda, użyj ciągów formatu liczbowego:

double total = "43.257"
MessageBox.Show(total.ToString("F"));
Helikopter szturmowy Harambe
źródło
2
Właściwie ta metoda robi okrągłe msdn.microsoft.com/en-us/library/…
elvin
13

używam price.ToString("0.00") do uzyskania wiodących zer

CMS
źródło
6

Funkcja C # wyrażona przez Kyle'a Rozendo:

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);
}
maxp
źródło
5

Co powiesz na dodanie jednego dodatkowego miejsca po przecinku, który ma zostać zaokrąglony, a następnie odrzucony:

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

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

źródło
3
To zabawne, jak
niedziałająca
5
Nie zadziała to w przypadku, gdy zaokrąglenie dotyczy więcej niż jednej cyfry powyżej wartości odcięcia. Na przykład 0.199999 zakończy się jako 0,20 z tym kodem zamiast 0,19.
Bernem
4

To działa dla mnie

string prouctPrice = Convert.ToDecimal(String.Format("{0:0.00}", Convert.ToDecimal(yourString))).ToString();
Zain Ali
źródło
2

Wiem, że to stary wątek, ale po prostu musiałem to zrobić. Podczas gdy inne podejścia tutaj działają, chciałem mieć łatwy sposób wpływania na wiele połączeń do string.format. Więc dodanie Math.Truncatedo wszystkich wywołań nie było dobrym rozwiązaniem. Ponadto, ponieważ część formatowania jest przechowywana w bazie danych, pogorszyło to jeszcze bardziej.

Dlatego stworzyłem niestandardowego dostawcę formatu, który pozwoliłby mi dodać obcinanie do ciągu formatującego, np .:

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

Implementacja jest dość prosta i można ją łatwo rozszerzyć na inne wymagania.

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;
    }
}
BJury
źródło
2

Miałem ten problem z Xamarin Forms i rozwiązałem go w ten sposób:

percent.ToString("0.##"+"%")
Diego Sanchez
źródło
1

Do pokazania waluty możesz użyć "C":

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

Wynik: $1.99

Roozbeh Zabihollahi
źródło
0

Możesz także napisać własny IFormatProvider , chociaż przypuszczam, że w końcu będziesz musiał pomyśleć o sposobie wykonania faktycznego obcięcia.

NET Framework obsługuje również formatowanie niestandardowe. Zwykle wiąże się to z utworzeniem klasy formatowania, która implementuje zarówno IFormatProvider, jak i ICustomFormatter . (msdn)

Przynajmniej byłby łatwy do ponownego użycia.

W CodeProject znajduje się artykuł o tym, jak zaimplementować własny IFormatProvider / ICustomFormatter . W takim przypadku najlepszym rozwiązaniem może być „rozszerzenie” istniejącego formatu liczbowego. Nie wygląda to zbyt mocno.

Benny Jobigan
źródło
0

Następujące mogą być używane tylko do wyświetlania, które używają właściwości String ..

double value = 123.456789;
String.Format("{0:0.00}", value);
Md. Shafiqur Rahman
źródło
Daje to „123,46”. Pytanie konkretnie nie wymaga zaokrąglania.
Tobberoth
0

Rozwiązanie:

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

(indexOfP + 1) +2 (ta liczba zależy od tego, ile liczb chcesz zachować. Daję dwa, ponieważ właściciel pytania chce).

劉鎮 瑲
źródło
0

Zwróć także uwagę na CultureInformation swojego systemu. Tutaj moje rozwiązanie bez zaokrąglania.

W tym przykładzie wystarczy zdefiniować zmienną MyValue jako double. W rezultacie otrzymasz sformatowaną wartość w zmiennej łańcuchowej NewValue .

Uwaga - ustaw również instrukcję 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);
Daniel
źródło