使用 Convert.ToDecimal() 会导致 C# 中的值四舍五入。如何克服这个问题?

Posted

技术标签:

【中文标题】使用 Convert.ToDecimal() 会导致 C# 中的值四舍五入。如何克服这个问题?【英文标题】:Using Convert.ToDecimal() causes rounding of value in C#. How to overcome this issue? 【发布时间】:2013-11-10 00:28:06 【问题描述】:

Some_Variable 具有从数据库返回的值 295523.93。 [DataType:money(Transact-SQL数据类型。使用的数据库是SQL2005)]

(十进制)Some_Variable 给出值 = 295523.93 [数据类型:十进制] (float)Some_Variable 给出值 = 295523.938 [DataType: float] (decimal)((float)Some_Variable) 给出值 = 295523.9 [DataType: decimal] Convert.ToDecimal((float)Some_Variable) 给出值 = 295523.9 [数据类型:十进制] ( (decimal)((double)Some_Variable) 给出值 = 295523.93 [DataType: decimal] Convert.ToDecimal((double)Some_Variable) 给出值 = 295523.93 [数据类型:十进制]

为什么在极少数情况下会给出 295523.9(由于项目运行超过 2 年而出现一次)

Convert.ToDecimal((float)Some_Variable) 给出值 = 295523.9 [数据类型:十进制]

我正在考虑使用 (decimal)Some_Variable,它给出的值 = 295523.93,但好奇除了与数字如何存储在内存中(二进制)有关之外,是否还有其他解释?

[编辑]:虽然实际值来自数据库,但为了重现问题,我在下面的示例中直接为其分配了值。请在下面的代码屏幕截图和 Watch 窗口中找到。

【问题讨论】:

你可能会感兴趣:***.com/questions/89203/… Some_Variable的类型是什么? (值的编译时类型和执行时类型都会很有用。) 如果小数导致问题,您是否尝试过使用双精度? 显示一些关于这种神秘类型“金钱”的实际代码和详细信息将有助于回答这个问题。 这完全正常。 float 类型的值只能存储 7 个有效数字。所以只有数字 2955239 可以是准确的,其余的只是随机噪声数字。将浮点数转换为十进制的隐式转换运算符知道这一点,并且简单地消除了噪音。 【参考方案1】:

float 具有极小的精度(对应于大约 7-8 个十进制数字)。例如,这些是您范围内的后续浮点数:

01001000100100000100110001111101 --> 295523.90625
01001000100100000100110001111110 --> 295523.9375
01001000100100000100110001111111 --> 295523.96875

因此,例如295523.92 的值将四舍五入为这些值中的第一个或第二个。由于第八位有效数字非常不准确,因此在转换为十进制时保留它是没有意义的。 documentation of Convert.ToDecimal(float) 中描述了这种行为(我强调):

此方法返回的 Decimal 值最多包含七个有效数字。 如果 value 参数包含超过 7 个有效数字,则使用四舍五入进行四舍五入。

295523.93 有八位有效数字。使用“四舍五入”将结果四舍五入为七位有效数字295523.9

【讨论】:

这是正确的。因此,即使在 decimal具有超高的精度。两个不同但“接近”的float 值可以投影到相同的decimal。存在一种解决方法。 @JeppeStigNielsen:正确,解决方法是,例如,float.ToString("r"),它输出一个“可以往返到相同数字的字符串”

以上是关于使用 Convert.ToDecimal() 会导致 C# 中的值四舍五入。如何克服这个问题?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Convert.ToDecimal(3.1922) 显示为 31922?

使用 Convert.ToDecimal() 会导致 C# 中的值四舍五入。如何克服这个问题?

Convert.ToDecimal 为简单字符串引发异常

VB.Net Convert ToDecimal 不适用于逗号

decimal.TryParse和Convert.ToDecimal+try{} catch{}的性能比较

在文本框中显示逗号 VB.net