4

我在尝试将两位小数相除然后显示结果时遇到问题。令人讨厌的是,这只发生在我们的服务器上,如果我在本地运行代码,它似乎工作得很好。这是我试图运行的代码


decimal dOne = -966.96M;
decimal dTwo = 2300M;

decimal dResult = Decimal.Round((dOne / dTwo), 28, 
                               MidpointRounding.AwayFromZero);

结果数字(从 Windows 计算器生成)是

-0.43346086956521739130434782608696

这总是会导致溢出异常:

System.OverflowException: Value was either too large or too small for a Decimal.
   at System.Decimal.FCallDivide(Decimal& result, Decimal d1, Decimal d2)
   at System.Decimal.op_Division(Decimal d1, Decimal d2)

这确实有点道理,因为结果数字超过小数点后 32 位,而小数点最多只能保留 28 位。但我不确定如何执行这种除法,因为它似乎将结果存储在小数点中输入内存,然后将其四舍五入并存储。我也尝试将其直接转换为字符串,而不是将其存储在十进制中,但这也有同样的问题。

有任何想法吗?我是否做了一些明显愚蠢的事情(很可能),有没有更好的方法来执行这个计算?

4

4 回答 4

4

应该运行良好。该除法不能保证返回完全准确的版本 - 例如,1 / 3m 可以正常工作。

结果显然不在范围之外decimal,因此在我看来,您的服务器上正在发生一些奇怪的事情。

要检查的一件事:是Decimal.Round抛出异常还是除法本身?将它们放入单独的语句中以找出答案。

于 2010-07-08T13:24:15.203 回答
4

尝试double在计算之前转换为,decimal如果需要,请尝试转换为之后:

decimal dOne = -966.96M;
decimal dTwo = 2300M;

double one = (double)dOne;
double two = (double)dTwo;

double result = one / two;

decimal dResult = (decimal)result; // Additional rounding may be necessary
于 2010-07-08T13:24:56.043 回答
1

Decimal.Round通过 Reflector 进行了查看,从我所看到的情况来看,它不会抛出OverflowException,所以我打赌异常来自该部门。您可以编辑答案以包含堆栈跟踪吗?

另外,您绝对确定分子和分母与您写的完全一样吗?当异常发生时,尝试将它们跟踪到控制台或日志文件。

你可以这样做:

decimal dOne = -966.96M; 
decimal dTwo = 2300M;  
try
{
  decimal dResult = Decimal.Round((dOne / dTwo), 28, MidpointRounding.AwayFromZero); 
}
catch (OverflowException)
{
  Console.WriteLine(dOne);
  Console.WriteLine(dTwo);
}

编辑:我想我FCallDivide在 SSCLI 中找到了代码。但是,在 .NET Framework 的发布版本中可能会有所不同,但我可以从 SSCLI 中的完成方式看到,无论如何都会以多种不同的方式生成溢出异常。代码相当复杂。如果您可以构建一个简短但完整的程序来演示该问题,我会将其作为错误提交给 Microsoft。这些输入中可能存在某种使算法混乱的位模式。

于 2010-07-08T13:37:22.847 回答
1

如果它发生在您的服务器上(您无法调试的地方)。您真的确定问题出在这些方面吗?

也许您可以只在单个 Decimal.Round 语句周围放置一个 try-catch 语句,并返回一些奇怪的值。您能否再次在您的服务器上运行此代码以查看此 catch 语句是否真的被调用,或者异常是否可能发生在其他地方。

于 2010-07-08T13:43:40.913 回答