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

半城伤御伤魂 提交于 2019-12-23 10:50:48

问题


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?
    (downtimeMinutes / (decimal)duration.TotalMinutes) * 100.0m : 0.0m;

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


回答1:


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.




回答2:


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)




回答3:


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


来源:https://stackoverflow.com/questions/6839369/automatically-cast-from-double-to-decimal-safely-is-the-following-safe

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!