如何在C#中安全地将double转换为decimal

5
我们使用decimal数据类型在SQL Server数据库中存储财务数据,并且需要6-8位小数的精度。当我们通过数据访问层将此值返回到我们的C#服务器时,它以decimal数据类型返回。
由于某些设计限制超出了我的控制范围,因此需要进行转换。将其转换为字符串不是问题。将其转换为double,则会产生舍入误差,因为MS文档中指出:“[从decimal到double的转换]可能会产生舍入误差,因为双精度浮点数的有效数字比decimal少。”
作为double(或string),我们可以在完成任何计算后将其舍入为2个小数位数,那么保证在舍入之前不丢失任何精度的正确方法是什么?

2
根据MSDN的说明,十进制数具有28-29位的精度,而双精度浮点数则具有15-16位。但是,如果您只存储6-8位数字,那么我认为四舍五入不会影响您。这可以很容易地进行单元测试以验证。 - nithins
2个回答

13
转换不会在前8位数字内产生错误。 double 具有15-16位精度,比decimal的28-29位要少,但据您所说足够满足您的需求。
然而您应该确立某种计划以避免在未来使用 double - 对于财务计算,它是一种不适合的数据类型。

1
比我的评论快15秒!(+1) :) - nithins
“这个数据类型不适合进行财务计算。”你有时间详细解释一下吗?这是我一直"知道"但不一定理解的事情。谢谢! :) - Dan J
6
金融计算通常用小数来表达,人们期望将(比如)0.01和0.01相加的结果恰好为0.02。但是在“double”中,既不能完全准确地表示0.01,也不能完全准确地表示0.02。当然,如果你(比如)除以3,仍会损失一些信息……但这对于每个人来说更容易理解(并且可能对政策做出决策),因为我们都习惯了十进制算术。一般来说,像身高和体重这样的自然不精确量适合使用“double”;而像精确的人工量这样的量则适合使用小数。 - Jon Skeet
http://msdn.microsoft.com/en-us/library/aa326763(v=vs.71).aspx 有一个非常好的双精度到十进制的 .Net 代码示例,应该会帮助您避免边缘情况。 - Nathan

4
如果你需要将数字保留两位小数,我认为“正确”的方式是存储一个整数,即对于12.34,你应该存储整数1234。这样就不会有双重舍入的问题了。
如果你必须使用double类型,这个方法依然适用;所有整数都可以在double类型中精确存储,所以同样可以使用这个技巧。

将double存储为int被认为是过早优化吗?1. 你需要记住在视图、更新和保存中进行转换。2. 如果业务需求发生变化,那么你会陷入大麻烦吗?如果财务部门后来想要4位小数点呢? - Holystream
此外,您通过使用此方法将最大/最小数字减少2位数。因此,现在您只有+/- 2000万,而不是+/- 20亿。是的,您可以使用Int64,但现在有什么意义呢? - Holystream
@Holystream:我认为他所说的“整数”并不是指Int32,而是指“整数”。许多旧系统不支持Int64Decimal,但支持Double,它可以容纳所有整数,精度不会丢失,最高可达4,503,599,627,370,496(或按100倍缩放,所有金额最高可达45,035,996,273,704.96美元)。 - supercat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接