2011-07-27 13 views
5

¿Es seguro echado de doble a decimal de la siguiente manera en C#:Emitir automáticamente de doble a decimal con seguridad: ¿Es seguro lo siguiente?

int downtimeMinutes = 90; 
TimeSpan duration = TimeSpan.FromHours(2d); 
decimal calculatedDowntimePercent = duration.TotalMinutes > 0? 
    (downtimeMinutes/(decimal)duration.TotalMinutes) * 100.0m : 0.0m; 

Si la respuesta es sí, entonces sin problemas, sólo voy a Marcar como aceptado.

+0

"seguro" en qué sentido - qué riesgos te preocupa? Imprecisión numérica? ¿Excepciones de tiempo de ejecución? ¿Algo más? –

+0

Las excepciones de tiempo de ejecución fueron mi única preocupación. Me preguntaba si el doble siempre arroja con éxito al decimal. – Lisa

Respuesta

2

Sí es seguro, ya que tiene una mayor precisión decimal

http://msdn.microsoft.com/en-us/library/364x0z75(VS.80).aspx

El compilador pondrá en moldes alrededor de los otros números no decimales, pero lo único que va a encajar en decimal * (ver advertencia).

- Advertencia

  • decimal no es un tipo de punto flotante. Su mandato es mantener siempre la precisión. Mientras que un número de coma flotante como el doble (que utilizo principalmente) compensa la precisión para acomodar números muy grandes). Los números muy grandes o muy pequeños no caben en decimal. Entonces, Lisa necesita preguntarse si la magnitud de la operación probablemente sea menor a 28 dígitos digitales significativos. 28 dígitos significativos son adecuados para la mayoría de los escenarios.

  • El punto flotante es bueno para números astronómicamente grandes o infinitamente pequeños ... o las operaciones intermedias que producen suficiente precisión. Debería buscar esto, pero el doble está bien para más o menos unos pocos miles de millones con una precisión de hasta varios puntos decimales (hasta 7 u 8?).

  • en las ciencias no tiene sentido medir más allá de la precisión de su equipo. En finanzas, a menudo la opción lógica es doble porque un doble es computacionalmente más eficiente para la mayoría de las situaciones (a veces quieren un poco más de precisión, pero la eficacia no vale la pena tirar para algo como el decimal). Al final, todos tenemos que obtener necesidades comerciales pragmáticas y de mapas para un dominio digital. Hay herramientas que tienen una representación numérica dinámica. Probablemente haya bibliotecas en .net para lo mismo. Sin embargo, ¿vale la pena? A veces lo es. A menudo es excesivo.

+1

Mayor precisión, pero el doble tiene un rango mucho más alto. –

+0

de acuerdo. Ver editar. – sgtz

+4

"todos encajarán en decimal" no es verdadero: 'Convert.ToDecimal (double.MaxValue)' lanzará 'OverflowException' – porges

3

En general, double ->decimal conversiones no son seguros, porque decimal tiene un rango menor.

Sin embargo, siempre que TotalMinutes sea menor que el valor máximo de decimal * estará bien. Esto es cierto, porque TimeSpan.MaxValue.TotalMinutes < (double)decimal.MaxValue (creo que TimeSpan usa internamente un long)

Entonces: sí.

*: (79,228,162,514,264,337,593,543,950,335 minutos es 1.1 x 10^13 veces la edad del universo)

+0

En mi dominio, el máximo realista para TotalMinutes es algo así como 4,000,000 pero con un límite superior absoluto de alrededor de 1,000,000,000. Entonces sí, será seguro en mi escenario. – Lisa

1

Sin, en general, fundición de doble a decimal no se siempre segura:

[TestCase(double.MinValue)] 
[TestCase(double.MaxValue)] 
[TestCase(double.NaN)] 
[TestCase(double.NegativeInfinity)] 
[TestCase(double.PositiveInfinity)] 
public void WillFail(double input) 
{ 
    decimal result = (decimal)input; // Throws OverflowException! 
} 

Como OP aclaró en un comentario a la pregunta, "seguro" siendo "no causa excepciones de tiempo de ejecución", lo anterior muestra que las excepciones pueden se producen al convertir un doble a un decimal.


Lo anterior es la respuesta genérica a la que muchos Googlers podrían haber venido aquí. Sin embargo, para responder también al específica pregunta por OP, aquí hay un fuerte indicio de que el código no va a lanzar excepciones, incluso en casos extremos:

[Test] 
public void SpecificCodeFromOP_WillNotFail_NotEvenOnEdgeCases() 
{ 
    int downtimeMinutes = 90; 
    foreach (TimeSpan duration in new[] { 
     TimeSpan.FromHours(2d), // From OP 
     TimeSpan.MinValue, 
     TimeSpan.Zero, 
     TimeSpan.MaxValue }) 
    { 
     decimal calculatedDowntimePercent = duration.TotalMinutes > 0 ? 
      (downtimeMinutes/(decimal)duration.TotalMinutes) * 100.0m : 0.0m; 
    } 
} 
Cuestiones relacionadas