Zobacz moją odpowiedź: String.Format()z 'G' powinno dostać to, czego chcesz. Zaktualizowałem moją odpowiedź z linkiem do standardowych formatów liczbowych. Bardzo przydatne.
Uszy psa
3
Można rzutować na liczbę dziesiętną double, a wartość domyślna ToStringdouble emituje końcowe zera. przeczytaj to
Shimmy Weitzhandler,
2
I prawdopodobnie będzie to kosztować mniej wydajności (w przypadku bardzo dużej liczby rekordów) niż przekazywanie funkcji „G” jako formatu ciągu znaków ToString.
Shimmy Weitzhandler,
4
Nie należy zamieniać ułamka dziesiętnego na podwójny, straci to na znaczeniu i może wprowadzić potęgę dwóch niedokładności zaokrągleń.
kristianp
Odpowiedzi:
167
Czy nie jest to takie proste, jeśli dane wejściowe są ciągiem znaków? Możesz użyć jednego z tych:
Powinno to działać dla wszystkich danych wejściowych.
Aktualizacja Sprawdź standardowe formaty liczbowe , które musiałem jawnie ustawić specyfikator dokładności na 29, ponieważ dokumentacja jasno stwierdza:
Jeśli jednak liczba jest liczbą dziesiętną, a specyfikator dokładności jest pominięty, zawsze używana jest notacja stałoprzecinkowa, a końcowe zera są zachowywane
Uważaj na wartości takie jak 0,000001. Format G29 przedstawi je w możliwie najkrótszy sposób, więc przełączy się na notację wykładniczą. string.Format("{0:G29}", decimal.Parse("0.00000001",System.Globalization.CultureInfo.GetCultureInfo("en-US")))da jako wynik „1E-08”.
Uważaj na wartości takie jak 0,000001. Format G29 przedstawi je w możliwie najkrótszy sposób, więc przełączy się na notację wykładniczą. string.Format ("{0: G29}", decimal.Parse ("0.00000001", System.Globalization.CultureInfo.GetCultureInfo ("en-US"))) zwróci jako wynik „1E-08”
Konrad
15
@Konrad - czy jest sposób na uniknięcie notacji naukowej dla liczb, które mają 5 lub 6 miejsc po przecinku?
Jill,
202
Napotkałem ten sam problem, ale w przypadku, gdy nie mam kontroli nad wyjściem do łańcucha, którym zajęła się biblioteka. Po przyjrzeniu się szczegółom implementacji typu Decimal (patrz http://msdn.microsoft.com/en-us/library/system.decimal.getbits.aspx ) wpadłem na zgrabną sztuczkę (tutaj jako rozszerzenie metoda):
Ta odpowiedź jest własna, ponieważ w przeciwieństwie do praktycznie każdej innej odpowiedzi na to pytanie (a nawet całego tematu) jest faktycznie DZIAŁA i robi to, o co prosi OP.
Coxy
2
czy liczba zer jest tutaj dokładną wielkością, czy po prostu pokrywa większość oczekiwanych wartości?
Simon_Weaver,
3
MSDN stwierdza: „Współczynnikiem skalowania jest niejawnie liczba 10, podniesiona do wykładnika z zakresu od 0 do 28”, co rozumiem, że liczba dziesiętna będzie miała co najwyżej 28 cyfr po przecinku. Dowolna liczba zer> = 28 powinna działać.
Thomas Materna
2
To najlepsza odpowiedź! Liczba w odpowiedzi ma 34 cyfry, 1a po niej 33 cyfry, 0ale to tworzy dokładnie to samo decimalwystąpienie, co liczba z 29 cyframi, jedną 1i 28 0znakami. Tak jak powiedział @ThomasMaterna w swoim komentarzu. Nie System.Decimalmoże mieć więcej niż 29 cyfr (liczby z początkowymi cyframi większe niż 79228...mogą mieć łącznie tylko 28 cyfr). Jeśli chcesz mieć więcej końcowych zer, pomnóż przez 1.000...mzamiast dzielić. Można również Math.Roundodciąć kilka zer, na przykład Math.Round(27.40000m, 2)daje 27.40m, więc zostało tylko jedno zero.
Jeppe Stig Nielsen
2
Świetna sztuczka, ale NIE działa na Mono i nie jest gwarantowana do pracy z wersjami funkcji .NET
To wspaniała odpowiedź. Jest to bardzo proste i możesz dokładnie zobaczyć, co się dzieje, zamiast używać magicznego programu do formatowania ciągów.
Timothy Gonzalez
9
Fajnie, ale nie będzie działać w przypadku kultur używających przecinka jako separatora dziesiętnego. Musisz użyćCulture.NumberFormat.NumberDecimalSeparator
blearyeye
1
Najlepsze podejście. Wszystko inne jest niepotrzebnie skomplikowane. Pamiętaj tylko, aby zawsze sprawdzić, czy Twój numer zawiera przecinek dziesiętny.
RRM
1
Aby być rozszerzeniem, brakuje „this” przed parametrem: public static string DecimalToString (this decimal dec)
João Antunes
Bardzo dziękuję za komentarze. Zaktualizowałem odpowiedź o nową wersję ze wskazówkami.
x7BiT
19
Użyj #symbolu hash ( ), aby wyświetlać końcowe 0 tylko wtedy, gdy jest to konieczne. Zobacz testy poniżej.
Nie ma odpowiedzi. Nie usuwasz końcowych zer, usuwasz precyzję. Proponowana metoda num1.ToString("0.##")powinna zwrócić 13.1534545765(bez zmian), ponieważ nie ma żadnych końcowych zer.
Jan 'splite' K.
I właśnie dlatego wyświetlam odpowiedzi na moje trzy proponowane dane wejściowe, aby użytkownicy mogli zobaczyć, jak działa moje rozwiązanie.
Fizzix
Nie odpowiada na pytanie, nawet jeśli wymienisz proponowane dane wejściowe.
Dave Friedel
2
Głosowałbym za tym 10 razy, gdybym mógł. Dokładnie to, czego potrzebowałem!
SubqueryCrunch
1
Doskonała odpowiedź na pytanie. NAJLEPSZA odpowiedź moim zdaniem. Komentarz, że usuwa precyzję, jest poprawny, ale nie o to chodziło. Najważniejsze - tego potrzebuję. Moi użytkownicy zazwyczaj wprowadzają liczby całkowite, może około 2,5, ale muszę obsługiwać 3 cyfry poza przecinkiem. Dlatego chcę im podać to, co wpisali, a nie kilka zer, których nie wprowadzili. np. Console.Write ($ "num3 = {num3: 0. ##}"); => num3 = 30
Zauważ, że jeśli vtak 0m, wynikiem twojego kodu jest pusty ciąg zamiast "0".
Sam
2
Tak. Powinien wynosić „0. ########”.
PRMan
2
Podejście na bardzo niskim poziomie, ale uważam, że byłby to najbardziej wydajny sposób przy użyciu tylko szybkich obliczeń całkowitych (bez powolnego analizowania ciągów i metod uwzględniających kulturę):
publicstaticdecimalNormalize(thisdecimal d){int[] bits =decimal.GetBits(d);int sign = bits[3]&(1<<31);int exp =(bits[3]>>16)&0x1f;uint a =(uint)bits[2];// Top bitsuint b =(uint)bits[1];// Middle bitsuint c =(uint)bits[0];// Bottom bitswhile(exp >0&&((a %5)*6+(b %5)*6+ c)%10==0){uint r;
a =DivideBy10((uint)0, a,out r);
b =DivideBy10(r, b,out r);
c =DivideBy10(r, c,out r);
exp--;}
bits[0]=(int)c;
bits[1]=(int)b;
bits[2]=(int)a;
bits[3]=(exp <<16)| sign;returnnewdecimal(bits);}privatestaticuintDivideBy10(uint highBits,uint lowBits,outuint remainder){ulong total = highBits;
total <<=32;
total = total |(ulong)lowBits;
remainder =(uint)(total %10L);return(uint)(total /10L);}
@ Damien, tak, i zauważ, że dla tych puropoz (nic nie poczujesz, chyba że zrobisz miliard rekordów), po pierwsze dlatego, że double jest szybsze, po drugie, ponieważ przekazanie formatu ciągu do funkcji ToString kosztuje więcej wydajności niż nie przekazywanie parametrów. znowu nic nie poczujesz, dopóki nie będziesz pracować nad miliardami płyt.
Shimmy Weitzhandler,
1
Nie musisz określać G, double.ToStringponieważ domyślnie usuwa końcowe zera.
Shimmy Weitzhandler,
4
Uważaj na wartości takie jak 0,000001. Zostaną one przedstawione w notacji wykładniczej. double.Parse ("0.00000001", System.Globalization.CultureInfo.GetCultureInfo ("en-US")). ToString () da wynik "1E-08"
Konrad
17
NIGDY tego nie rób. Zwykle powodem, dla którego masz ułamek dziesiętny, jest to, że precyzyjnie reprezentujesz liczbę (a nie w przybliżeniu tak, jak podwójna). To prawda, ten błąd zmiennoprzecinkowy jest prawdopodobnie dość mały, ale może spowodować wyświetlanie nieprawidłowych liczb, niemniej jednak
Adam Tegen
2
Ups, konwersja 128-bitowego typu danych (dziesiętnego) na 64-bitowy typ danych (podwójny) w celu formatowania nie jest dobrym pomysłem!
Zależy od tego, co reprezentuje twoja liczba i jak chcesz zarządzać wartościami: czy to waluta, czy potrzebujesz zaokrąglenia, czy obcięcia, czy potrzebujesz tego zaokrąglenia tylko do wyświetlenia?
Jeśli do wyświetlania rozważ formatowanie liczb w postaci x.ToString („”)
privatestaticdecimalTrim(thisdecimalvalue){var s =value.ToString(CultureInfo.InvariantCulture);return s.Contains(CultureInfo.InvariantCulture.NumberFormat.NumberDecimalSeparator)?Decimal.Parse(s.TrimEnd('0'),CultureInfo.InvariantCulture):value;}privatestaticdecimal?Trim(thisdecimal?value){returnvalue.HasValue?(decimal?)value.Value.Trim():null;}privatestaticvoidMain(string[] args){Console.WriteLine("=>{0}",1.0000m.Trim());Console.WriteLine("=>{0}",1.000000023000m.Trim());Console.WriteLine("=>{0}",((decimal?)1.000000023000m).Trim());Console.WriteLine("=>{0}",((decimal?)null).Trim());}
(I) -> Analizuj wartość dziesiętną z dowolnego źródła ciągu.
(II) -> Pierwsze: Rzutuj, aby podwoić to, aby usunąć końcowe zera. Po drugie: inne rzutowanie na dziesiętne, ponieważ nie istnieje niejawna konwersja z dziesiętnego na podwójny i odwrotnie)
Zakładasz, że wszystkie wartości, które mieszczą się w ułamku dziesiętnym, mieszczą się w podwójnym. Może to spowodować OverflowExeception. Możesz także stracić precyzję.
A co z lokalizacjami, które nie używają znaku „.”?
Martin Mulder,
w ogóle nie jest opcją w porównaniu z innymi podejściami w tym poście. Konwersja na ciąg znaków iz powrotem jest zawsze złą opcją manipulowania liczbami (przynajmniej ze względu na lokalizację)
Vladimir Semashkin
-11
spróbuj w ten sposób
string s ="2.4200";
s = s.TrimStart('0').TrimEnd('0','.');
możesz użyć subString()do tego metody, ale zgodnie z zamieszczonym tutaj pytaniem nie widzę żadnego takiego wymagania =)
Singleton
2
A co z lokalizacjami, które nie używają znaku „.”
Dave Hillier
10
Nie udaje się to żałośnie dla liczb, które są parzystą wielokrotnością 10,0.
Ben Voigt,
1
To, co powiedział @BenVoigt, jest całkowicie poprawne, ponieważ przykład "12300.00"zostanie przycięty "123". Innym efektem, który wydaje się niepożądany, jest to, że niektóre liczby, takie jak, "0.00"są przycinane aż do pustego ciągu ""(chociaż ta liczba jest szczególnym przypadkiem bycia całkowitą „wielokrotnością 10,0”).
String.Format()
z 'G' powinno dostać to, czego chcesz. Zaktualizowałem moją odpowiedź z linkiem do standardowych formatów liczbowych. Bardzo przydatne.double
, a wartość domyślnaToString
double emituje końcowe zera. przeczytaj toToString
.Odpowiedzi:
Czy nie jest to takie proste, jeśli dane wejściowe są ciągiem znaków? Możesz użyć jednego z tych:
Powinno to działać dla wszystkich danych wejściowych.
Aktualizacja Sprawdź standardowe formaty liczbowe , które musiałem jawnie ustawić specyfikator dokładności na 29, ponieważ dokumentacja jasno stwierdza:
Aktualizacja Konrad zaznaczył w komentarzach:
źródło
Napotkałem ten sam problem, ale w przypadku, gdy nie mam kontroli nad wyjściem do łańcucha, którym zajęła się biblioteka. Po przyjrzeniu się szczegółom implementacji typu Decimal (patrz http://msdn.microsoft.com/en-us/library/system.decimal.getbits.aspx ) wpadłem na zgrabną sztuczkę (tutaj jako rozszerzenie metoda):
Wykładnik dziesiętny jest zredukowany do tego, co jest potrzebne. Wywołanie ToString () na wyjściu dziesiętnym zapisze liczbę bez końcowego 0. Np
źródło
1
a po niej 33 cyfry,0
ale to tworzy dokładnie to samodecimal
wystąpienie, co liczba z 29 cyframi, jedną1
i 280
znakami. Tak jak powiedział @ThomasMaterna w swoim komentarzu. NieSystem.Decimal
może mieć więcej niż 29 cyfr (liczby z początkowymi cyframi większe niż79228...
mogą mieć łącznie tylko 28 cyfr). Jeśli chcesz mieć więcej końcowych zer, pomnóż przez1.000...m
zamiast dzielić. Można równieżMath.Round
odciąć kilka zer, na przykładMath.Round(27.40000m, 2)
daje27.40m
, więc zostało tylko jedno zero.Moim zdaniem bezpieczniej jest używać niestandardowych ciągów formatu liczbowego .
źródło
Używam tego kodu, aby uniknąć naukowej notacji „G29”:
EDYCJA: przy użyciu systemu CultureInfo.NumberFormat.NumberDecimalSeparator:
źródło
Culture.NumberFormat.NumberDecimalSeparator
Użyj
#
symbolu hash ( ), aby wyświetlać końcowe 0 tylko wtedy, gdy jest to konieczne. Zobacz testy poniżej.źródło
num1.ToString("0.##")
powinna zwrócić13.1534545765
(bez zmian), ponieważ nie ma żadnych końcowych zer.Znalazłem eleganckie rozwiązanie z http://dobrzanski.net/2009/05/14/c-decimaltostring-and-how-to-get-rid-of-trailing-zeros/
Gruntownie
źródło
v
tak0m
, wynikiem twojego kodu jest pusty ciąg zamiast"0"
.Podejście na bardzo niskim poziomie, ale uważam, że byłby to najbardziej wydajny sposób przy użyciu tylko szybkich obliczeń całkowitych (bez powolnego analizowania ciągów i metod uwzględniających kulturę):
źródło
a
ib
) w każdej chwili iteracji, jeśli i tak wszystkie są równe zero. Jednak wtedy znalazłem to zaskakująco proste rozwiązanie, które z łatwością pokonuje to, co ty i ja wymyśliliśmy pod względem wydajności .To zadziała:
Lub jeśli Twoja wartość początkowa to
string
:Zwróć uwagę na ten komentarz .
źródło
double.ToString
ponieważ domyślnie usuwa końcowe zera.To jest proste.
Przetestowany.
Twoje zdrowie :)
źródło
Zależy od tego, co reprezentuje twoja liczba i jak chcesz zarządzać wartościami: czy to waluta, czy potrzebujesz zaokrąglenia, czy obcięcia, czy potrzebujesz tego zaokrąglenia tylko do wyświetlenia?
Jeśli do wyświetlania rozważ formatowanie liczb w postaci x.ToString („”)
http://msdn.microsoft.com/en-us/library/dwhawy9k.aspx i
http://msdn.microsoft.com/en-us/library/0c899ak8.aspx
Jeśli jest to tylko zaokrąglanie, użyj przeciążenia Math.Round, które wymaga przeciążenia MidPointRounding
http://msdn.microsoft.com/en-us/library/ms131274.aspx )
Jeśli otrzymujesz swoją wartość z bazy danych, rozważ rzutowanie zamiast konwersji: double value = (decimal) myRecord ["columnName"];
źródło
Możesz po prostu ustawić jako:
źródło
Jeśli chcesz zachować liczbę dziesiętną, spróbuj następującego przykładu:
źródło
Próba znalezienia bardziej przyjaznego rozwiązania DecimalToString ( https://stackoverflow.com/a/34486763/3852139 ):
Wynik:
źródło
Bardzo prostą odpowiedzią jest użycie TrimEnd (). Oto wynik,
Wynik wynosi 1 Jeśli moja wartość to 1,01, to na wyjściu będzie 1,01
źródło
value = 100
?Poniższego kodu można użyć, aby nie używać typu ciągu:
Zwraca 789,5
źródło
Obcinanie końcowych zer jest bardzo łatwe, rozwiąż je za pomocą rzutu dwustronnego:
(I) -> Analizuj wartość dziesiętną z dowolnego źródła ciągu.
(II) -> Pierwsze: Rzutuj, aby podwoić to, aby usunąć końcowe zera. Po drugie: inne rzutowanie na dziesiętne, ponieważ nie istnieje niejawna konwersja z dziesiętnego na podwójny i odwrotnie)
źródło
wypróbuj ten kod:
źródło
spróbuj w ten sposób
a następnie przekonwertuj to na float
źródło
subString()
do tego metody, ale zgodnie z zamieszczonym tutaj pytaniem nie widzę żadnego takiego wymagania =)"12300.00"
zostanie przycięty"123"
. Innym efektem, który wydaje się niepożądany, jest to, że niektóre liczby, takie jak,"0.00"
są przycinane aż do pustego ciągu""
(chociaż ta liczba jest szczególnym przypadkiem bycia całkowitą „wielokrotnością 10,0”).