2012-01-02 16 views
15

Durante una conversazione su IRC, qualcuno ha sottolineato quanto segue:Il decimale memorizza la precisione dalla stringa analizzata in C#? Quali sono le implicazioni?

decimal.Parse("1.0000").ToString() // 1.0000 
decimal.Parse("1.00").ToString() // 1.00 

Come/Perché il tipo decimal mantengono la precisione (o, meglio, cifre significative) in questo modo? Avevo l'impressione che i due valori fossero uguali, non distinti.

Ciò solleva anche altre domande:

  • Come è il numero di cifre significative deciso durante le operazioni matematiche?
  • Il numero di cifre significative viene mantenuto durante la serializzazione?
  • La cultura attuale influisce sul modo in cui viene gestita?
+10

Per quanto riguarda [come] (http://msdn.microsoft.com/en-us/library/system.decimal.aspx) vale: "La rappresentazione binaria di un valore decimale è costituita da un segno a 1 bit, un numero intero a 96 bit e un fattore di scala utilizzato per dividere il numero intero a 96 bit e specificare quale parte di esso è una frazione decimale Il fattore di scala è implicitamente il numero 10, elevato a un esponente compreso tra 0 e 28. " - il fattore di scala è un componente discreto. –

+0

@ pst - Quindi il fattore di scala è il solo responsabile di cifre significative? Ad esempio, '1.0000' è' 10000/10^4' e '1.00' è' 100/10^2' – Polynomial

risposta

9

Come viene deciso il numero di cifre significative durante le operazioni matematiche?

Questo indicata nel ECMA-334 C# 4 specifica 11.1.7 p.112

Un decimale è rappresentato come numero intero scalato da una potenza di dieci. Per i decimali con un valore assoluto inferiore a 1,0 m, il valore è esatto a almeno il 28 ° decimale. Per i decimali con un valore assoluto maggiore o uguale a 1,0 m, il valore è esatto almeno a 28 cifre.

Il numero di cifre significative viene mantenuto durante la serializzazione?

Sì lo fa, con seriallization il valore e la sua precisione non cambia

[Serializable] 
public class Foo 
{ 
    public decimal Value; 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     decimal d1 = decimal.Parse("1.0000"); 
     decimal d2 = decimal.Parse("1.00"); 

     Debug.Assert(d1 ==d2); 

     var foo1 = new Foo() {Value = d1}; 
     var foo2 = new Foo() {Value = d2}; 

     IFormatter formatter = new BinaryFormatter(); 
     Stream stream = new FileStream("data.bin", FileMode.Create, FileAccess.Write, FileShare.None); 
     formatter.Serialize(stream, d1); 
     stream.Close(); 

     formatter = new BinaryFormatter(); 
     stream = new FileStream("data.bin", FileMode.Open, FileAccess.Read, FileShare.Read); 
     decimal deserializedD1 = (decimal)formatter.Deserialize(stream); 
     stream.Close(); 

     Debug.Assert(d1 == deserializedD1); 

     Console.WriteLine(d1); //1.0000 
     Console.WriteLine(d2); //1.00 
     Console.WriteLine(deserializedD1); //1.0000 

     Console.Read(); 
    } 
} 

Ha la cultura corrente influisce sul modo in cui questo viene gestito?

La cultura corrente riguarda solo il modo in cui un decimale può essere analizzato da una stringa, ad esempio può gestire '.' o ',' come simbolo di punto decimale specifico per la cultura o simbolo di valuta, se lo fornite, ad es. "£ 123.4500". La cultura non cambia il modo in cui un oggetto viene memorizzato internamente e non influenza la sua precisione.

Internamente, decimal has una mantissa, un esponente e un segno, quindi non c'è spazio per nient'altro.

+0

Ottima risposta! Grazie mille :) – Polynomial

1

Un decimal costituito da un numero intero di 96 bit e un fattore di scala (numero di cifre dopo il punto decimale), che varia da 0 a 28. Pertanto:

  • 1,000 diventa 1000 con fattore di scala 3.
+0

In che modo il fattore di scala viene influenzato dalle operazioni matematiche e dalla serializzazione? – Polynomial

+0

Il fattore di scala è incluso nella forma serializzata del valore Decimale, come ottenuto chiamando il metodo GetBits. Inoltre, come specificato nella documentazione, "[t] gli zero di binario non influenzano il valore di un numero decimale nelle operazioni aritmetiche o di confronto." –

1

Oltre a inviare che vedo qui, io personalmente aggiungere una nota a margine:

sempre durante le manipolazioni di persistenza con floating point/decimale/numeri doppi considerano il culture ci si trovi, o sei andando a salvare in. Il codice come qui scritto è il primo, ma passaggio definitivo al pasticcio completo e non architettura indipendente dalla cultura.

Utilizzare Decimal.Parse (String, IFormatProvider).

A mio parere, i metodi (Parse From/To) che la mancanza del parametro Culture devono essere rimossi dalla libreria per costringere uno sviluppatore a pensare a questo aspetto molto importante.

Problemi correlati