2011-07-27 12 views
5

È sicuro gettato dal doppio al decimale nel modo seguente in C#:Trasmetti automaticamente da doppio a decimale in modo sicuro: il seguente è sicuro?

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

Se la risposta è sì, allora nessuna confusione, mi limiterò a contrassegnare come accettata.

+0

"Safe" in che senso - quali rischi ti preoccupi? Imprecisione numerica? Eccezioni di runtime? Qualcos'altro? –

+0

Le eccezioni del runtime erano la mia unica preoccupazione. Mi chiedevo se il doppio sempre riuscisse a decimali. – Lisa

risposta

2

Sì, è sicuro, perché ha una maggiore precisione decimale

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

Il compilatore metterà in calchi in giro gli altri numeri non decimali, ma saranno tutti inserirsi in decimale * (vedi avvertimento).

- Caveat

  • decimale non è un tipo a virgola mobile. Il suo mandato è di mantenere sempre la precisione. Considerando che un numero in virgola mobile come il doppio (che io per lo più uso) fa un compromesso sulla precisione per accogliere numeri molto grandi). Numeri molto grandi o molto piccoli non si adattano al decimale. Quindi Lisa ha bisogno di chiedersi se l'entità dell'operazione sarà probabilmente inferiore a 28 cifre digitali significative. 28 cifre significative sono adeguate per la maggior parte degli scenari.

  • Il punto in virgola mobile è valido per numeri astronomici di grandi dimensioni o infintessibilmente piccoli ... o operazioni tra loro che danno abbastanza precisione. Dovrei cercare questo, ma il doppio va bene per più o meno qualche miliardo con precisione fino a diversi decimali (fino a 7 o 8?).

  • nelle scienze non ha senso misurare oltre la precisione della vostra attrezzatura. In finanza, spesso la scelta logica è doppia perché un doppio è computazionalmente più efficiente per la maggior parte delle situazioni (a volte vogliono un po 'più precisione, ma l'efficienza non vale la pena di buttare via per qualcosa di simile al decimale). Alla fine dobbiamo tutti ottenere pragmatiche e mappare le esigenze aziendali verso un dominio digitale. Ci sono strumenti là fuori che hanno una rappresentazione numerica dinamica. Probabilmente ci sono librerie in .net per lo stesso. Tuttavia, ne vale la pena? A volte lo è. Spesso è eccessivo.

+1

Maggiore precisione, ma il doppio ha una gamma molto più alta. –

+0

concordato. Vedi modifica. – sgtz

+4

"saranno tutti in decimale" non è vero: 'Convert.ToDecimal (double.MaxValue)' genererà 'OverflowException' – porges

3

In generale, double ->decimal conversioni non sono sicuro, perché decimal ha una gamma più ridotta.

Tuttavia, fino a quando TotalMinutes è inferiore al valore massimo decimal * andrà bene. Questo è vero, perché TimeSpan.MaxValue.TotalMinutes < (double)decimal.MaxValue (credo che TimeSpan utilizzi internamente uno long.)

Quindi: sì.

*: (79,228,162,514,264,337,593,543,950,335 minuti è 1.1 × 10^13 volte l'età dell'universo)

+0

Nel mio dominio il massimo realistico per TotalMinutes è qualcosa come 4.000.000 ma con un limite superiore assoluto di circa 1.000.000.000. Quindi sì, sarà sicuro nel mio scenario. – Lisa

1

No, in generale, colata da doppia a decimale non è sempre sicuro:

[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! 
} 

Come OP chiarito in un commento alla domanda, "sicura" essere "non causa eccezioni fase di esecuzione", gli spettacoli di cui sopra che le eccezioni possono verificarsi quando lancia un doppio a un decimale.


Quanto sopra è la risposta generica molti Googler potrebbero Sono venuto qui per questo. Tuttavia, per rispondere anche alla specifica domanda da OP, ecco una forte indicazione che il codice non generare eccezioni, anche in casi limite:

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