使用 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# 中的值四舍五入。如何克服这个问题?
VB.Net Convert ToDecimal 不适用于逗号