开发者

Automatically cast from double to decimal safely: Is the following safe?

Is it safe to cast from double to decimal in the following manner in C#:

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

If the answer is yes, then no fuss, I'll just mark as accepted.


In general, double -> decimal conversions aren't safe, because decimal has a smaller range.

However, as long as TotalMinutes is less than the maximum decimal value* it will be fine. This is true, because TimeSpan.MaxValue.TotalMinutes < (double)decimal.MaxValue (I believe TimeSpan uses a long internally.)

So: yes.

*: (79,228,162,514,264,337,593,543,950,335 minutes is 1.1×10^13 times the age of the universe)


No, in general, casting from double to decimal is not always safe:

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

As OP clarified in a comment to the question, "safe" being "doesn't cause run time exceptions", the above shows that exceptions can occur when casting a double to a decimal.


The above is the generic answer many Googlers might've come here for. However, to also answer the specific question by OP, here's a strong indication that the code will not throw exceptions, even on edge cases:

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


Yes it is safe, because decimal has greater precision

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

The compiler will put in casts around the other non decimal numbers, but they'll all fit into decimal * (see caveat).

-- Caveat

  • Decimal is not a floating point type. Its mandate is to always uphold precision. Whereas a floating point number such as double (which I mostly use) makes a tradeoff on precision to accommodate very large numbers). Very large or very small numbers will not fit into decimal. So Lisa needs to ask herself if the magnitude of the operation is likely to be less than 28 significant digital digits. 28 significant digits are adequate for most scenarios.

  • Floating point is good for astronomically large or infintessimally small numbers... or operations inbetween that yield enough accuracy. I should look this up, but double is okay for plus or minus a few billion with accuracy of up to several decimal points (up to 7 or 8?).

  • in the sciences there's no point measuring beyond the accuracy of your equipment. In finance, often the logical choice is double because a double is computationally more efficient for most situations (sometimes they want a bit more accuracy, but the efficiency is not worth throwing away for something like decimal). In the end we all have to get pragmatic and map business needs to a digital domain. There are tools out there that have a dynamic number representation. Probably there are libraries in .net for the same. However, is it worth it? Sometimes it is. Often it's overkill.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜