Entfernen Sie nachgestellte Nullen

177

Ich habe einige Felder von einer Sammlung als zurückgegeben

2.4200
2.0044
2.0000

Ich möchte Ergebnisse wie

2.42
2.0044
2

Ich habe es mit versucht String.Format, aber es kehrt zurück 2.0000und setzt es so, dass auch N0die anderen Werte gerundet werden.

Zo hat
quelle
3
anfangs Datensatztyp ist Zeichenfolge?
Singleton
2
Siehe meine Antwort: String.Format()mit 'G' sollte bekommen, was Sie wollen .. Ich habe meine Antwort mit einem Link zu Standard-Zahlenformaten aktualisiert. Sehr benutzerfreundlich.
Hundeohren
3
Eine Dezimalstelle kann in umgewandelt werden double, und die Standardeinstellung ToStringfür double gibt die nachfolgenden Nullen aus. Lesen Sie dies
Shimmy Weitzhandler
2
Und es wird wahrscheinlich weniger Leistung kosten (Zwischenzeiten mit sehr vielen Datensätzen) als das Übergeben des "G" als Zeichenfolgenformat an die ToStringFunktion.
Shimmy Weitzhandler
4
Sie sollten eine Dezimalstelle nicht in ein Doppel konvertieren, da dies an Bedeutung verliert und möglicherweise zwei Rundungsungenauigkeiten auftreten.
Kristianp

Antworten:

166

Ist es nicht so einfach, wenn die Eingabe eine Zeichenfolge ist? Sie können eine davon verwenden:

string.Format("{0:G29}", decimal.Parse("2.0044"))

decimal.Parse("2.0044").ToString("G29")

2.0m.ToString("G29")

Dies sollte für alle Eingaben funktionieren.

Update Schauen Sie sich die numerischen Standardformate an. Ich musste den Präzisionsspezifizierer explizit auf 29 setzen, da in den Dokumenten eindeutig angegeben ist:

Wenn die Zahl jedoch eine Dezimalzahl ist und der Präzisionsspezifizierer weggelassen wird, wird immer die Festkommanotation verwendet und nachfolgende Nullen bleiben erhalten

Update Konrad wies in den Kommentaren darauf hin:

Achten Sie auf Werte wie 0,000001. Das G29-Format präsentiert sie auf kürzestem Weg, sodass zur Exponentialschreibweise gewechselt wird. string.Format("{0:G29}", decimal.Parse("0.00000001",System.Globalization.CultureInfo.GetCultureInfo("en-US")))gibt als Ergebnis "1E-08".

Hundeohren
quelle
1
Von allen Antworten waren bei Ihnen die wenigsten Schritte erforderlich. Vielen Dank, dass Sie Dog Ears.
Zo hat
4
var d = 2,0 m; d.ToString ("G");
Dave Hillier
3
@ Dave Hillier - Ich verstehe, ich habe meine Antwort korrigiert. Prost. [expliziten 'Präzisionsspezifizierer' hinzugefügt]
Dog Ears
16
Achten Sie auf Werte wie 0,000001. Das G29-Format präsentiert sie so schnell wie möglich, sodass zur Exponentialschreibweise gewechselt wird. string.Format ("{0: G29}", decimal.Parse ("0.00000001", System.Globalization.CultureInfo.GetCultureInfo ("en-US"))) gibt als Ergebnis "1E-08" aus
Konrad
15
@Konrad - Gibt es eine Möglichkeit, die wissenschaftliche Notation für Zahlen mit 5 oder 6 Dezimalstellen zu vermeiden?
Jill
202

Ich bin auf das gleiche Problem gestoßen, aber in einem Fall, in dem ich keine Kontrolle über die Ausgabe in einen String habe, der von einer Bibliothek erledigt wurde. Nachdem ich mich mit Details bei der Implementierung des Dezimaltyps befasst hatte (siehe http://msdn.microsoft.com/en-us/library/system.decimal.getbits.aspx ), kam ich auf einen tollen Trick (hier als Erweiterung) Methode):

public static decimal Normalize(this decimal value)
{
    return value/1.000000000000000000000000000000000m;
}

Der Exponententeil der Dezimalstelle wird auf das reduziert, was benötigt wird. Wenn Sie ToString () auf der Ausgangsdezimalstelle aufrufen, wird die Zahl ohne nachgestellte 0 geschrieben

1.200m.Normalize().ToString();
Thomas Materna
quelle
28
Diese Antwort gehört, weil im Gegensatz zu jeder anderen Antwort auf diese Frage (und sogar das gesamte Thema) tatsächlich ARBEITEN ist und das tut, was das OP verlangt.
Coxy
2
Ist die Anzahl der Nullen hier eine exakte Größe oder nur, um die meisten erwarteten Werte abzudecken?
Simon_Weaver
3
In der MSDN heißt es: "Der Skalierungsfaktor ist implizit die Zahl 10, die auf einen Exponenten zwischen 0 und 28 angehoben wird." Ich verstehe, dass die Dezimalzahl höchstens 28 Stellen nach dem Dezimalpunkt hat. Eine beliebige Anzahl von Nullen> = 28 sollte funktionieren.
Thomas Materna
2
Das ist die beste Antwort! Die Zahl in der Antwort hat 34 Ziffern, 1gefolgt von 33 0-s, aber das erzeugt genau die gleiche decimalInstanz wie eine Zahl mit 29 Ziffern, eins 1und 28 0-s. Genau wie @ThomasMaterna in seinem Kommentar sagte. Nein System.Decimalkann mehr als 29 Ziffern haben (Zahlen mit führenden Ziffern größer als insgesamt 79228...nur 28 Ziffern). Wenn Sie mehr nachgestellte Nullen wünschen , multiplizieren Sie mit, 1.000...manstatt zu teilen. Auch Math.Roundkönnen einige Nullen abhacken, zum Beispiel Math.Round(27.40000m, 2)gibt 27.40m, so dass nur eine Null links.
Jeppe Stig Nielsen
2
Toller Trick, funktioniert aber NICHT unter Mono und es wird nicht garantiert, dass er an Feature-Versionen von .NET
Bigjim
87

Meiner Meinung nach ist es sicherer, benutzerdefinierte Zeichenfolgen im numerischen Format zu verwenden .

decimal d = 0.00000000000010000000000m;
string custom = d.ToString("0.#########################");
// gives: 0,0000000000001
string general = d.ToString("G29");
// gives: 1E-13
Michał Powaga
quelle
25
+1 für die einzige Antwort, die auf einem stabilen, dokumentierten Verhalten beruht.
Sinelaw
3
Sie sollten dort 28 '#' Zeichen einfügen , siehe blackwasp.co.uk/DecimalTrailingZeroes.aspx .
Jaime Hablutzel
32

Ich benutze diesen Code, um die wissenschaftliche Notation "G29" zu vermeiden:

public static string DecimalToString(this decimal dec)
{
    string strdec = dec.ToString(CultureInfo.InvariantCulture);
    return strdec.Contains(".") ? strdec.TrimEnd('0').TrimEnd('.') : strdec;
}

BEARBEITEN: Verwenden des Systems CultureInfo.NumberFormat.NumberDecimalSeparator:

public static string DecimalToString(this decimal dec)
{
    string sep = CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;
    string strdec = dec.ToString(CultureInfo.CurrentCulture);
    return strdec.Contains(sep) ? strdec.TrimEnd('0').TrimEnd(sep.ToCharArray()) : strdec;
}
x7BiT
quelle
1
Dies ist eine wunderbare Antwort. Es ist sehr einfach und Sie können genau sehen, was passiert, anstatt einen magischen String-Formatierer zu verwenden.
Timothy Gonzalez
9
Schön, aber es funktioniert nicht für Kulturen, die Komma als Dezimaltrennzeichen verwenden. Sie müssten verwendenCulture.NumberFormat.NumberDecimalSeparator
blearyeye
1
Bester Ansatz. Alles andere ist unnötig kompliziert. Denken Sie daran, immer zu überprüfen, ob Ihre Zahl einen Dezimalpunkt enthält.
RRM
1
Um eine Erweiterung zu sein, fehlt das "this" vor dem Parameter: public static string DecimalToString (this decimal dec)
João Antunes
Vielen Dank für die Kommentare. Ich habe die Antwort mit einer neuen Version mit den Tipps aktualisiert.
x7BiT
19

Verwenden Sie das #Symbol hash ( ), um nachfolgende Nullen nur bei Bedarf anzuzeigen. Siehe die Tests unten.

decimal num1 = 13.1534545765;
decimal num2 = 49.100145;
decimal num3 = 30.000235;

num1.ToString("0.##");       //13.15%
num2.ToString("0.##");       //49.1%
num3.ToString("0.##");       //30%
Fizzix
quelle
7
Keine Antwort. Sie entfernen keine nachgestellten Nullen, sondern die Genauigkeit. Ihre vorgeschlagene Methode num1.ToString("0.##")sollte zurückgegeben werden 13.1534545765(keine Änderung), da keine nachgestellten Nullen vorhanden sind.
Jan 'splite' K.
Und genau deshalb zeige ich die Antworten auf meine drei vorgeschlagenen Eingaben an, damit Benutzer sehen können, wie meine Lösung funktioniert.
Fizzix
Die Frage wird nicht beantwortet, selbst wenn Sie die vorgeschlagenen Eingaben auflisten.
Dave Friedel
2
Ich würde dies 10 Mal verbessern, wenn ich könnte. Genau das, was ich brauchte!
SubqueryCrunch
1
Perfekte Antwort auf die Frage. BESTE Antwort meiner Meinung nach. Kommentar, dass es Präzision entfernt, ist richtig, aber das war nicht die Frage. Am wichtigsten - es ist was ich brauche. Meine Benutzer geben normalerweise ganze Zahlen ein, vielleicht etwa 2,5, aber ich muss 3 Stellen hinter dem Dezimalpunkt unterstützen. Also möchte ich ihnen geben, was sie eingegeben haben, nicht mit einer Reihe von Nullen, die sie nicht eingegeben haben. zB Console.Write ($ "num3 = {num3: 0. ##}"); => num3 = 30
bobwki
13

Ich fand eine elegante Lösung von http://dobrzanski.net/2009/05/14/c-decimaltostring-and-how-to-get-rid-of-trailing-zeros/

Grundsätzlich

decimal v=2.4200M;

v.ToString("#.######"); // Will return 2.42. The number of # is how many decimal digits you support.
DHornpout
quelle
1
Beachten Sie, dass , wenn vist 0m, ist das Ergebnis des Codes eine leere Zeichenfolge statt "0".
Sam
2
Ja. Es sollte "0" sein. ######## ".
PRMan
2

Ein Ansatz auf sehr niedriger Ebene, aber ich glaube, dies wäre der performanteste Weg, wenn nur schnelle Ganzzahlberechnungen (und keine langsamen String-Parsing- und kultursensitiven Methoden) verwendet werden:

public static decimal Normalize(this decimal d)
{
    int[] bits = decimal.GetBits(d);

    int sign = bits[3] & (1 << 31);
    int exp = (bits[3] >> 16) & 0x1f;

    uint a = (uint)bits[2]; // Top bits
    uint b = (uint)bits[1]; // Middle bits
    uint c = (uint)bits[0]; // Bottom bits

    while (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;
    return new decimal(bits);
}

private static uint DivideBy10(uint highBits, uint lowBits, out uint remainder)
{
    ulong total = highBits;
    total <<= 32;
    total = total | (ulong)lowBits;

    remainder = (uint)(total % 10L);
    return (uint)(total / 10L);
}
Bigjim
quelle
1
Ich hatte versucht , diesen Weg zu gehen, aber es weiter optimiert , so dass es wirklich viel schneller als Ihr bekam, durch zB nicht die Teilung hallo und Mitte Ints (Ihr aund b) in jeder Iteration , während , wenn sie alle Null ohnehin sind. Dann fand ich jedoch diese überraschend einfache Lösung, die auch das übertrifft, was Sie und ich in Bezug auf die Leistung entwickelt haben .
Eugene Beresovsky
2

Das wird funktionieren:

decimal source = 2.4200m;
string output = ((double)source).ToString();

Oder wenn Ihr Anfangswert ist string:

string source = "2.4200";
string output = double.Parse(source).ToString();

Achten Sie auf diesen Kommentar .

Shimmy Weitzhandler
quelle
2
@Damien, ja, und beachten Sie, dass für diese Zwecke (Sie werden nichts fühlen, wenn Sie nicht eine Milliarde Datensätze machen), erstens, weil double schneller ist, zweitens, weil das Übergeben eines String-Formats an die ToString-Funktion mehr Leistung kostet als nicht Parameter übergeben. Auch hier werden Sie nichts spüren, wenn Sie nicht an Millionen von Aufzeichnungen arbeiten.
Shimmy Weitzhandler
1
Sie müssen kein G angeben, da standardmäßig double.ToStringnachgestellte Nullen entfernt werden.
Shimmy Weitzhandler
4
Achten Sie auf Werte wie 0,000001. Diese werden in Exponentialschreibweise dargestellt. double.Parse ("0.00000001", System.Globalization.CultureInfo.GetCultureInfo ("en-US")). ToString () gibt als Ergebnis "1E-08" aus
Konrad
17
Tu das NIEMALS. Normalerweise haben Sie eine Dezimalstelle, weil Sie eine Zahl genau darstellen (nicht ungefähr wie bei einem Doppel). Zugegeben, dieser Gleitkommafehler ist wahrscheinlich ziemlich klein, könnte aber dennoch dazu führen, dass falsche Zahlen
angezeigt werden
2
Autsch, die Konvertierung eines 128-Bit-Datentyps (dezimal) in einen 64-Bit-Datentyp (doppelt) zur Formatierung ist keine gute Idee!
avl_sweden
2

Das ist einfach.

decimal decNumber = Convert.ToDecimal(value);
        return decNumber.ToString("0.####");

Geprüft.

Prost :)

Rakesh
quelle
1

Hängt davon ab, was Ihre Nummer darstellt und wie Sie die Werte verwalten möchten: Ist es eine Währung, benötigen Sie eine Rundung oder Kürzung, benötigen Sie diese Rundung nur für die Anzeige?

Wenn für die Anzeige eine Formatierung in Betracht gezogen wird, lauten die Zahlen x.ToString ("")

http://msdn.microsoft.com/en-us/library/dwhawy9k.aspx und

http://msdn.microsoft.com/en-us/library/0c899ak8.aspx

Wenn es sich nur um eine Rundung handelt, verwenden Sie die Math.Round-Überladung, die eine MidPointRounding-Überladung erfordert

http://msdn.microsoft.com/en-us/library/ms131274.aspx )

Wenn Sie Ihren Wert aus einer Datenbank erhalten, ziehen Sie das Casting anstelle der Konvertierung in Betracht: double value = (decimal) myRecord ["columnName"];

Gulden
quelle
0

Sie können einfach einstellen als:

decimal decNumber = 23.45600000m;
Console.WriteLine(decNumber.ToString("0.##"));
Danilo Ferreira
quelle
1
Damit das funktioniert, sollten Sie achtundzwanzig '#' Zeichen anstelle von nur zwei setzen.
Jaime Hablutzel
Ja, ich habe seine Frage falsch verstanden ... = /
Danilo Ferreira
0

Wenn Sie die Dezimalzahl beibehalten möchten, versuchen Sie folgendes Beispiel:

number = Math.Floor(number * 100000000) / 100000000;
phuongnd
quelle
0

Versuch, eine benutzerfreundlichere Lösung für DecimalToString zu finden ( https://stackoverflow.com/a/34486763/3852139 ):

private static decimal Trim(this decimal value)
{
    var s = value.ToString(CultureInfo.InvariantCulture);
    return s.Contains(CultureInfo.InvariantCulture.NumberFormat.NumberDecimalSeparator)
        ? Decimal.Parse(s.TrimEnd('0'), CultureInfo.InvariantCulture)
        : value;
}

private static decimal? Trim(this decimal? value)
{
    return value.HasValue ? (decimal?) value.Value.Trim() : null;
}

private static void Main(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());
}

Ausgabe:

=>1
=>1.000000023
=>1.000000023
=>
Dmitri
quelle
-1

Eine sehr einfache Antwort ist die Verwendung von TrimEnd (). Hier ist das Ergebnis,

double value = 1.00;
string output = value.ToString().TrimEnd('0');

Ausgabe ist 1 Wenn mein Wert 1,01 ist, ist meine Ausgabe 1,01

Raj De Inno
quelle
4
Was ist wenn value = 100?
Stephen Drew
4
@ Raj De Inno Selbst wenn der Wert 1,00 ist, ist die Ausgabe "1". nicht "1"
Simba
-1

Der folgende Code kann verwendet werden, um den Zeichenfolgentyp nicht zu verwenden:

int decimalResult = 789.500
while (decimalResult>0 && decimalResult % 10 == 0)
{
    decimalResult = decimalResult / 10;
}
return decimalResult;

Rückgabe 789.5

Raul Minon
quelle
-2

Das Abschneiden von nachgestellten Nullen ist sehr einfach und kann mit einer Duplex-Besetzung gelöst werden:

        decimal mydecimal = decimal.Parse("1,45000000"); //(I)
        decimal truncate = (decimal)(double)mydecimal;   //(II)

(I) -> Analysiert den Dezimalwert aus einer beliebigen Zeichenfolgenquelle.

(II) -> Zuerst: Um dies zu verdoppeln, entfernen Sie die nachgestellten Nullen. Zweitens: Andere Umwandlung in Dezimalzahl, da keine implizite Konvertierung von Dezimalzahl in Doppel- und umgekehrt existiert.

amedriveroperez
quelle
5
Sie gehen davon aus, dass alle Werte, die in eine Dezimalstelle passen würden, in ein Doppel passen. Dies kann eine OverflowExeception verursachen. Sie können auch die Präzision verlieren.
Martin Mulder
-2

Versuchen Sie diesen Code:

string value = "100";
value = value.Contains(".") ? value.TrimStart('0').TrimEnd('0').TrimEnd('.') : value.TrimStart('0');
Raju
quelle
Warum zwei Antworten, mein Freund?
Raging Bull
2
Was ist mit Gebietsschemas, die kein '.' Verwenden?
Martin Mulder
im Vergleich zu anderen Ansätzen in diesem Beitrag überhaupt keine Option. Das Konvertieren in Zeichenfolge und zurück ist immer eine schlechte Option, um Zahlen zu manipulieren (zumindest wegen des Gebietsschemas)
Vladimir Semashkin
-11

versuche es so

string s = "2.4200";

s = s.TrimStart('0').TrimEnd('0', '.');

und konvertiere das dann in float

Singleton
quelle
1
Sie können subString()Methode dafür verwenden, aber laut der hier geposteten Frage sehe ich keine solche Anforderung =)
Singleton
2
Was ist mit Gebietsschemas, in denen '.' Nicht verwendet wird?
Dave Hillier
10
Dies schlägt kläglich für Zahlen fehl, die ein gerades Vielfaches von 10,0 sind.
Ben Voigt
1
Was @BenVoigt gesagt hat, ist völlig richtig, da ein Beispiel "12300.00"darauf zugeschnitten wird "123". Ein weiterer Effekt, unerwünscht scheint , ist , dass einige Zahlen, wie die "0.00"ganze Art und Weise beschnitten werden nach unten auf die leere Zeichenfolge ""(obwohl diese Zahl ist ein Spezialfall ein integrales „Vielfach von 10,0“).
Jeppe Stig Nielsen