2011-04-22 15 views
14

¿Hay alguna diferencia práctica entre los valores .net decimal de 1 my 1.0000 m?¿Hay alguna diferencia práctica entre los valores .net decimal 1m y 1.0000m?

El almacenamiento interno es diferente:

1m  : 0x00000001 0x00000000 0x00000000 0x00000000 
1.0000m : 0x000186a0 0x00000000 0x00000000 0x00050000 

Pero, ¿existe una situación en la que el conocimiento de "cifras significativas" sería utilizado por un método en el BCL?

Pregunto porque estoy trabajando en un modo de comprimir el espacio requerido para valores decimales para almacenamiento de disco o transporte de red y estoy jugando con la idea de "normalizar" el valor antes de almacenarlo para mejorar su compresibilidad. Pero, me gustaría saber si es probable que cause problemas en el futuro. Supongo que debería estar bien, pero solo porque no veo ningún método o propiedad que exponga la precisión del valor. ¿Alguien sabe de otra manera?

Respuesta

4

La única razón que se me ocurre es invocar `ToString devuelve la representación textual exacta en el código fuente.

Console.WriteLine(1m); // 1 
Console.WriteLine(1.000m); // 1.000 
+1

-1: ¿Cómo podría saber "ToString" algo sobre el código fuente? –

+0

Interesante. Tendré que dar som Pensé si me importaba o no. – MarkPflug

+0

@John - Claramente lo es. – ChaosPandion

11

La razón de la diferencia en la codificación se debe a que los decimales de tipo de datos almacena el número como un número entero (número entero de 96 bits), con una escala que se utiliza para formar el divisor para obtener el número fraccionario. El valor es esencialmente

integer/10^scale 

Internamente el tipo decimal se representa como 4 Int32, consulte la documentación de Decimal.GetBits para más detalle. En resumen, getbits devuelve una matriz de 4 Int32s, donde cada elemento representa la porción de seguimiento de la codificación decimal

Element 0,1,2 - Represent the low, middle and high 32 bits on the 96 bit integer 
Element 3  - Bits 0-15 Unused 
       Bits 16-23 exponent which is the power of 10 to divide the integer by 
       Bits 24-30 Unused 
       Bit 31 the sign where 0 is positive and 1 is negative 

Así que en su ejemplo, muy simplemente poner cuando 1.0000m se codifica como un número decimal de la representación real es 10000/10^4 mientras que 1m se representa como 1/10^0 matemáticamente el mismo valor codificado de manera diferente.

Si usa los operadores .NET nativos para el tipo de decimal y no manipula/compara los bits/bytes usted mismo, debe estar seguro.

También notará que las conversiones de cadena también tomarán en cuenta esta representación binaria y producirán diferentes cadenas, por lo que debe tener cuidado en ese caso si alguna vez confía en la representación de cadena.

+0

Pequeño nitpick: No es Byte 1,2,3 sino más bien (cuarteto de 4 bytes). O tal vez podría decir que los primeros 12 bytes contienen el valor entero. –

+0

@Matt Brunell, ¡tienes toda la razón! Gracias por eso corregí la respuesta en consecuencia. –

5

El tipo decimal rastrea la escala porque es importante en aritmética. Si lo hace la multiplicación larga, a mano, de dos números — por ejemplo, 3,14 * 5,00 — el resultado tiene 6 dígitos de precisión y una escala de 4.

Para la multiplicación, ignorar los puntos decimales (por ahora) y tratar los dos números como enteros.

3.14 
* 5.00 
------ 
    0000 -- 0 * 314 (0 in the one's place) 
00000 -- 0 * 314 (0 in the 10's place) 
157000 -- 5 * 314 (5 in the 100's place) 
------ 
157000 

Eso le da los resultados sin escala. Ahora, cuente el número total de dígitos a la derecha del punto decimal en la expresión (que sería 4) e inserte el punto decimal 4 lugares a la izquierda:

15.7000 

ese resultado, mientras que un valor equivalente al 15.7, es más preciso que el valor 15.7. El valor 15.7000 tiene 6 dígitos de precisión y una escala de 4; 15.7 tiene 3 dígitos de precisión y una escala de 1

Si uno está tratando de hacer aritmética de precisión, es importante realizar un seguimiento de la precisión y la escala de valores y sus resultados ya que le dice algo acerca de la precisión de sus resultados (tenga en cuenta que la precisión no es lo mismo que la precisión: mida algo con una regla graduada en 1/10 de pulgada y lo mejor que pueda decir sobre la medida resultante, sin importar cuántos ceros finales ponga a la derecha del punto decimal es que tiene una precisión de, como mucho, un 1/10th de una pulgada. Otra forma de expresarlo sería decir que su medición es exacta, a lo sumo, dentro de +/- 5/100ths del valor indicado.

+0

Desafortunadamente, la forma en que la precisión de las pistas 'Decimal' no mantiene confiablemente ninguna información sobre la precisión de los números involucrados. La división por números que no son de la forma 2^n * 5^n dará la cantidad máxima representable de dígitos, independientemente de si esos dígitos representan alguna precisión real, y nada indica cuando la resta da como resultado una cancelación catastrófica. – supercat

Cuestiones relacionadas