安全地自动从双精度投射到十进制:以下是否安全?

在C#中以下列方式从double转换为十进制是安全的:

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

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

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

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

编译器会在其他非十进制数字周围放置强制转换,但它们都适合十进制*(参见警告)。

– 警告

  • 十进制不是浮点类型。 它的使命是始终坚持精确性。 浮点数(例如double(我主要使用))会对精度进行折衷以适应非常大的数字)。 非常大或非常小的数字将不适合十进制。 因此Lisa需要问自己,操作的幅度是否可能低于28个重要的数字位。 对于大多数情况,28位有效数字已足够。

  • 浮点适用于天文数字大或数量非常小的数字……或者中间的操作可以产生足够的精度。 我应该仔细研究一下,但是对于正负数十亿可以加倍,精度高达几个小数点(最多7或8?)。

  • 在科学领域,没有必要超出设备的准确度。 在财务方面,通常逻辑选择是双重的,因为对于大多数情况,双精度计算效率更高(有时它们需要更高的准确性,但效率不值得丢弃,如十进制)。 最后,我们都必须务实并将业务需求映射到数字领域。 有些工具有动态数字表示。 可能在.net中有相同的库。 但是,值得吗? 有时它是。 通常它太过分了。

通常, double – > decimal转换不安全,因为decimal的范围较小。

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

所以:是的。

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

,通常, 从double到decimal的转换并不总是安全的

 [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在对该问题的评论中澄清,“ 安全 ”是“ 不会导致运行时exception ”,上面显示了将双精度转换为小数时可能发生exception。


以上是许多Google员工可能会来这里的通用答案。 但是,为了回答OP的具体问题,这里强烈表明代码不会抛出exception,即使是在边缘情况下:

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