2011-02-18 14 views
5

Estamos almacenando datos financieros en una base de datos de SQL Server utilizando el tipo de datos decimal y necesitamos 6-8 dígitos de precisión en el decimal. Cuando recuperamos este valor a través de nuestra capa de acceso a datos en nuestro servidor C#, vuelve como el tipo de datos decimales.Cómo convertir de forma segura de un doble a un decimal en C#

Debido a algunas limitaciones de diseño que están fuera de mi control, es necesario convertirlo. Convertir a una cadena no es un problema. La conversión a un doble es como dice la documentación de Microsoft "[la conversión de decimal a doble] puede producir errores de redondeo porque un número de punto flotante de precisión doble tiene menos dígitos significativos que un decimal".

Como el doble (o cadena) podemos redondear a 2 lugares decimales después de realizar cualquier cálculo, entonces, ¿cuál es la forma "correcta" de hacer la conversión decimal para garantizar que no perdemos ninguna precisión antes del redondeo ?

+2

Según MSDN, el decimal tiene una precisión de 28-29 dígitos y el doble tiene 15-16. Pero si solo está almacenando de 6 a 8 dígitos, entonces creo que el redondeo no lo afectará. Esto podría ser probado en una unidad fácilmente para ver. – nithins

Respuesta

13

La conversión no producirá errores dentro de los primeros 8 dígitos. double tiene 15-16 dígitos de precisión, menos que el 28-29 de decimal, pero suficiente para sus propósitos por el sonido de la misma.

Definitivamente debe poner en marcha algún tipo de plan para evitar el uso de double en el futuro, sin embargo, es un tipo de datos inadecuados para los cálculos financieros.

+1

¡Completa mi comentario por 15 segundos! (+1) :) – nithins

+0

* "es un tipo de datos inadecuado para los cálculos financieros." * ¿Podrías explicarlo más a fondo? Es una de esas cosas que siempre he "conocido" y no necesariamente entendido. ¡Aclamaciones! :) –

+6

@djacobson: los cálculos financieros normalmente * se expresan * en decimales, se espera que el resultado de agregar (digamos) 0,01 y 0,01 sea * exactamente * 0,02. Eso es un truco en "doble" donde ni 0.01 ni 0.02 pueden representarse exactamente. Por supuesto, aún perderá algo de información si (digamos) se divide por 3 ... pero es mucho más fácil para que todos entiendan (y probablemente decidan sobre la política) ya que todos estamos acostumbrados a la aritmética decimal. En términos generales, las cantidades naturalmente imprecisas como la altura y el peso son buenas para el doble; las cantidades exactas, hechas por el hombre son buenas para decimales. –

3

Si redondeas a 2dp, IMO la forma "correcta" sería almacenar un número entero que es el múltiplo, es decir, para 12.34 almacenas el número entero 1234. No hay más dobles inflexiones.

Si tiene que usar doble, esto sigue funcionando; se garantiza que todos los enteros se almacenan exactamente en doble, por lo que aún se usa el mismo truco.

+0

¿No almacenaría el doble como int consideró la optimización prematura? 1. Deberá recordar hacer conversiones a la vista, actualizaciones y guardar. 2. Si el requisito de negocio cambia, ¿entonces está en un gran problema? ¿Qué pasa si el departamento de finanzas luego quiere 4 decimales? – Holystream

+0

también, está reduciendo el número máximo/mínimo en 2 dígitos para usar esto. Entonces, en lugar de +/- 2 billones, ahora solo tiene +/- 20 millones. Sí, podrías usar Int64, pero ¿cuál es el punto ahora? – Holystream

+0

@Holystream: Por "entero" no creo que signifique 'Int32'; Creo que quiere decir "números enteros". Muchos sistemas anteriores no admitían 'Int64' o' Decimal', pero admitían 'Double', que puede acomodar, sin pérdida de precisión, todos los números enteros hasta 4,503,599,627,370,496 (o, escalando por un factor de 100, todo el centavo sube a $ 45,035,996,273,704.96) – supercat

Cuestiones relacionadas