自动安全地从双精度型转换为十进制型:以下安全吗?

发布于 2024-11-26 15:47:46 字数 304 浏览 3 评论 0原文

在 C# 中按以下方式从双精度型转换为十进制是否安全:

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

如果答案是肯定的,那么不用大惊小怪,我将标记为已接受。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

花开半夏魅人心 2024-12-03 15:47:46

一般来说,double -> decimal 转换并不安全,因为 decimal 的范围较小。

但是,只要 TotalMinutes 小于最大 decimal 值*就可以了。这是真的,因为 TimeSpan.MaxValue.TotalMinutes (double)decimal.MaxValue (我相信 TimeSpan 在内部使用 long。)

所以:是的。

*:(79,228,162,514,264,337,593,543,950,335分钟是宇宙年龄的1.1×10^13倍)

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)

相对绾红妆 2024-12-03 15:47:46

,一般来说,从双精度型转换为十进制并不总是安全

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

正如OP在对该问题的评论中所澄清的那样,“ safe”是“不会导致运行时异常”,上面显示将双精度型转换为小数时可能发生异常。


以上是许多 Google 员工来到这里的通用答案。然而,为了回答OP提出的特定问题,这里强烈表明代码不会抛出异常,即使在边缘情况下也是如此:

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

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;
    }
}
心是晴朗的。 2024-12-03 15:47:46

是的,它是安全的,因为十进制具有更高的精度

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

编译器将对其他非十进制数字进行强制转换,但它们都会适合十进制 * (参见警告)。

--
警告

  • Decimal 不是浮点类型。它的使命是始终保持精确性。而浮点数,例如 double (我主要使用它)则在精度上进行了权衡以适应非常大的数字)。非常大或非常小的数字不适合十进制。所以Lisa需要问问自己,运算的幅度是否有可能小于28位有效数字。 28 位有效数字足以满足大多数情况。

  • 浮点适用于天文大数或无限小数......或产生足够精度的介于两者之间的运算。我应该查一下,但是 double 可以精确到小数点后几位(最多 7 或 8?),可以精确到正负几十亿。

  • 在科学中,测量超出设备的准确性是没有意义的。在金融领域,通常逻辑选择是 double,因为在大多数情况下,double 在计算上效率更高(有时他们想要更高的准确性,但效率不值得为小数之类的东西而丢弃)。最后,我们都必须务实,将业务需求映射到数字领域。有些工具具有动态数字表示形式。 .net 中可能有相同的库。然而,这值得吗?有时是这样。通常这是矫枉过正的。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文