Rimuovi gli zeri finali


177

Ho alcuni campi restituiti da una raccolta come

2.4200
2.0044
2.0000

Voglio risultati come

2.42
2.0044
2

Ho provato con String.Format, ma ritorna 2.0000e lo imposta per N0arrotondare anche gli altri valori.


3
inizialmente il tipo di record è stringa ??
Singleton,

2
Vedi la mia risposta: String.Format()con 'G' dovresti ottenere quello che vuoi .. ho aggiornato la mia risposta con un link ai formati numerici standard. Molto utile.
Orecchie da cane,

3
È possibile eseguire il cast di un decimale doublee il valore predefinito ToStringper double emette gli zeri finali. leggi questo
Shimmy Weitzhandler il

2
E probabilmente costerà meno prestazioni (intervalli di una grande quantità di record) rispetto al passaggio della "G" come formato stringa alla ToStringfunzione.
Shimmy Weitzhandler,

4
Non dovresti convertire un decimale in un doppio, perderà significato e potrebbe introdurre il potere di due inesattezze di arrotondamento.
kristianp,

Risposte:


167

Non è così semplice, se l'ingresso È una stringa? Puoi usare uno di questi:

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

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

2.0m.ToString("G29")

Questo dovrebbe funzionare per tutti gli input.

Aggiornamento Dai un'occhiata ai formati numerici standard che ho dovuto impostare esplicitamente lo specificatore di precisione su 29, come chiaramente indicato dai documenti:

Tuttavia, se il numero è un decimale e l'identificatore di precisione viene omesso, viene sempre utilizzata la notazione a virgola fissa e gli zeri finali vengono conservati

Aggiornamento Konrad sottolineato nei commenti:

Fai attenzione a valori come 0,000001. Il formato G29 li presenterà nel modo più breve possibile, quindi passerà alla notazione esponenziale. string.Format("{0:G29}", decimal.Parse("0.00000001",System.Globalization.CultureInfo.GetCultureInfo("en-US")))darà "1E-08" come risultato.


1
Di tutte le risposte, la tua ha avuto il minor numero di passaggi. Grazie orecchie da cane.
Zo ha il

4
var d = 2,0 m; d.ToString ( "G");
Dave Hillier,

3
@Dave Hillier - Vedo, ho corretto la mia risposta. Saluti. [aggiunto esplicito 'specificatore di precisione']
Dog Ears

16
Fai attenzione a valori come 0,000001. Il formato G29 li presenterà nel modo più breve possibile, quindi passerà alla notazione esponenziale. string.Format ("{0: G29}", decimal.Parse ("0.00000001", System.Globalization.CultureInfo.GetCultureInfo ("en-US"))) darà come risultato "1E-08"
Konrad

15
@Konrad - c'è un modo per evitare la notazione scientifica per i numeri che hanno 5 o 6 cifre decimali?
Jill,

202

Ho riscontrato lo stesso problema, ma in un caso in cui non ho il controllo dell'output su stringa, che è stato curato da una libreria. Dopo aver esaminato i dettagli nell'implementazione del tipo Decimale (vedi http://msdn.microsoft.com/en-us/library/system.decimal.getbits.aspx ), ho trovato un trucco accurato (qui come estensione metodo):

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

La parte esponente del decimale è ridotta a ciò che è necessario. Chiamando ToString () sul decimale di output si scriverà il numero senza alcun 0. 0 ad es

1.200m.Normalize().ToString();

29
Questa risposta è valida perché, diversamente da qualsiasi altra risposta su questa domanda (e persino sull'intero argomento), in realtà FUNZIONA e fa ciò che l'OP sta chiedendo.
Coxy,

2
il numero di 0 è una quantità esatta qui o solo per coprire i valori più previsti?
Simon_Weaver,

3
MSDN afferma "Il fattore di ridimensionamento è implicitamente il numero 10, elevato a un esponente compreso tra 0 e 28", che intendo come il numero decimale avrà al massimo 28 cifre oltre il punto decimale. Qualsiasi numero di zeri> = 28 dovrebbe funzionare.
Thomas Materna,

2
Questa è la risposta migliore! Il numero nella risposta ha 34 cifre, 1seguito da 33 0-s, ma crea esattamente la stessa decimalistanza di un numero con 29 cifre, una 1e 28 0-s. Proprio come ha detto @ThomasMaterna nel suo commento. No System.Decimalpuò contenere più di 29 cifre (i numeri con cifre iniziali maggiori di 79228...possono contenere solo 28 cifre). Se vuoi più zeri finali, moltiplica 1.000...minvece di dividere. Inoltre, Math.Roundpuò tagliare alcuni zeri, ad esempio Math.Round(27.40000m, 2)27.40m, quindi ne rimane solo uno zero.
Jeppe Stig Nielsen,

2
Grande trucco ma NON funziona su Mono e non è garantito che funzioni su versioni di funzionalità di .NET
Bigjim


32

Uso questo codice per evitare la notazione scientifica "G29":

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

EDIT: utilizzando il sistema 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;
}

1
Questa è una risposta meravigliosa È molto semplice e puoi vedere esattamente cosa sta succedendo invece di usare un formattatore di stringhe magiche.
Timothy Gonzalez,

9
Bello, ma non funzionerà per le culture che usano la virgola per il separatore decimale. Dovresti usareCulture.NumberFormat.NumberDecimalSeparator
blearyeye il

1
Il miglior approccio. Tutto il resto è inutilmente complicato. Ricorda sempre di verificare se il tuo numero contiene un punto decimale.
RRM

1
Per essere un'estensione manca il "questo" prima del parametro: stringa statica pubblica DecimalToString (questo decimale decimale)
João Antunes

Grazie mille per i commenti Ho aggiornato la risposta con una nuova versione con i suggerimenti.
x7BiT

19

Utilizzare il #simbolo hash ( ) per visualizzare gli 0 finali solo quando necessario. Vedi i test di seguito.

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%

7
Non una risposta Non stai rimuovendo gli zeri finali, stai rimuovendo la precisione. Il metodo proposto num1.ToString("0.##")dovrebbe restituire 13.1534545765(nessuna modifica) perché non vi sono zeri finali.
Jan 'splite' K.

Ed è esattamente per questo che sto mostrando le risposte ai miei tre input proposti in modo che gli utenti possano vedere come funziona la mia soluzione.
Fizzix,

Non risponde alla domanda anche se si elencano gli input proposti.
Dave Friedel, il

2
Se lo potessi, lo valuterò 10 volte. Esattamente quello di cui avevo bisogno!
SubqueryCrunch

1
Risposta perfetta alla domanda. MIGLIORE risposta a mio avviso. Commenta che rimuove la precisione è corretta, ma non era il quesiton. Più importante - è quello di cui ho bisogno. I miei utenti in genere inseriranno numeri interi, forse qualcosa come 2.5, ma devo supportare 3 cifre oltre il punto decimale. Quindi voglio dare loro ciò che hanno inserito, non con un mucchio di zero in cui non sono entrati. ad es. Console.Write ($ "num3 = {num3: 0. ##}"); => num3 = 30
bobwki


2

Un approccio di livello molto basso, ma credo che questo sarebbe il modo più performante usando solo calcoli interi rapidi (e nessun metodo di analisi delle stringhe lento e metodi sensibili alla cultura):

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

1
Avevo provato a seguire questa strada, ma l'ho ottimizzato ulteriormente in modo che diventasse molto più veloce della tua, ad esempio non dividendo l' hi e la metà (in ae b) in ogni iterazione se sono comunque tutti zero. Tuttavia, ho trovato questa soluzione sorprendentemente semplice, che batte facilmente anche ciò che io e te abbiamo realizzato in termini di prestazioni .
Eugene Beresovsky

2

Questo funzionerà:

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

O se il tuo valore iniziale è string:

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

Presta attenzione a questo commento .


2
@Damien, sì, e nota, che per queste puroposi (non sentirai nulla se non fai un miliardo di record), in primo luogo perché il doppio è più veloce, in secondo luogo, perché passare un formato di stringa alla funzione ToString costa più prestazioni che no passando parametri. di nuovo, non sentirai nulla se non lavori su milioni di dischi.
Shimmy Weitzhandler il

1
Non è necessario specificare G, perché double.ToStringrimuove gli zeri finali per impostazione predefinita.
Shimmy Weitzhandler il

4
Fai attenzione a valori come 0,000001. Questi saranno presentati nella notazione esponenziale. double.Parse ("0.00000001", System.Globalization.CultureInfo.GetCultureInfo ("en-US")). ToString () darà come risultato "1E-08" come risultato
Konrad

17
Non farlo MAI. Di solito, il motivo per cui hai un decimale è perché stai rappresentando un numero con precisione (non approssimativamente come fa un doppio). Certo, questo errore in virgola mobile è probabilmente piuttosto piccolo, ma potrebbe comportare la visualizzazione di numeri errati, tuttavia
Adam Tegen,

2
Inoltre, convertire un tipo di dati a 128 bit (decimale) in un tipo di dati a 64 bit (doppio) per la formattazione, non è una buona idea!
avl_sweden l'

2

Questo è semplice

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

Provato.

Saluti :)


1

Dipende da cosa rappresenta il tuo numero e come vuoi gestire i valori: è una valuta, hai bisogno di arrotondamenti o troncamenti, hai bisogno di questi arrotondamenti solo per la visualizzazione?

Se per la visualizzazione prendere in considerazione la formattazione, i numeri sono x.ToString ("")

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

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

Se si tratta solo di arrotondamento, utilizzare il sovraccarico Math.Round che richiede un sovraccarico MidPointRounding

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

Se ottieni il tuo valore da un database, considera il casting invece della conversione: double value = (decimal) myRecord ["columnName"];


0

Puoi semplicemente impostare come:

decimal decNumber = 23.45600000m;
Console.WriteLine(decNumber.ToString("0.##"));

1
Affinché funzioni, dovresti mettere ventotto caratteri "#" anziché solo due.
Jaime Hablutzel,

sì, ho frainteso la sua domanda ... = /
Danilo Ferreira il

0

Nel caso in cui si desideri mantenere il numero decimale, provare il seguente esempio:

number = Math.Floor(number * 100000000) / 100000000;

0

Prova di fare una soluzione più amichevole di DecimalToString ( 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());
}

Produzione:

=>1
=>1.000000023
=>1.000000023
=>

-1

La risposta molto semplice è usare TrimEnd (). Ecco il risultato,

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

L'output è 1 Se il mio valore è 1.01, l'output sarà 1.01


4
E se value = 100?
Stephen Drew,

4
@Raj De Inno Anche se il valore è 1.00 l'output che sta dando è "1" non "1"
Simba

-1

Il seguente codice potrebbe essere utilizzato per non utilizzare il tipo di stringa:

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

Restituisce 789,5


-2

Troncare gli zeri finali è molto semplice, risolvere con un cast duplex:

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

(I) -> Valore decimale di analisi da qualsiasi origine stringa.

(II) -> Primo: Cast per raddoppiare questo rimuovere gli zeri finali. Secondo: altro cast in decimale perché non esiste una conversione implicita da decimale a doppio e viceversa)


5
Assumi tutti i valori che rientrerebbero in un decimale, in un doppio. Ciò può causare un OverflowExeception. È inoltre possibile perdere la precisione.
Martin Mulder,

-2

prova questo codice:

string value = "100";
value = value.Contains(".") ? value.TrimStart('0').TrimEnd('0').TrimEnd('.') : value.TrimStart('0');

Perché due risposte, amico mio?
Raging Bull

2
Che dire dei locali che non usano "."?
Martin Mulder,

non è affatto un'opzione rispetto ad altri approcci in questo post. La conversione in stringa e ritorno è sempre una cattiva opzione per manipolare i numeri (almeno a causa delle
impostazioni

-11

prova così

string s = "2.4200";

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

e poi convertilo in float


1
puoi usare il subString()metodo per questo, ma secondo la domanda pubblicata qui, non vedo alcun requisito del genere =)
Singleton

2
Che dire dei locali che non usano "."
Dave Hillier,

10
Ciò fallisce miseramente per i numeri che sono anche un multiplo di 10.0.
Ben Voigt,

1
Ciò che @BenVoigt ha detto è del tutto corretto, come "12300.00"verrà tagliato un esame "123". Un altro effetto che sembra indesiderabile è che alcuni numeri, come quelli, "0.00"sono tagliati fino alla stringa vuota ""(anche se questo numero è un caso speciale di essere un "multiplo di 10,0" integrale).
Jeppe Stig Nielsen
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.