如何克服丢失的便士?

时间:2011-08-02 16:38:17

标签: .net currency

我将为一家为金融机构编程的公司工作,我将会花很多钱。在此之前,这对我来说并不是一个主要的问题,因为我一直在做小钱的事情而且Double在某些时候已经足够了,但现在甚至1便士也很重要。

我想每个人都可能知道

Dim mValue as Decimal = 100 'seems the best type for now
mValue = mValue / 3
Console.WriteLine(mValue)
Console.ReadLine()

mValue = mValue * 3
Console.WriteLine(mValue)
'Outputs 99.9999999999999999999999999... and never hits 100

那么我怎样才能克服这个问题并找到更好的精确结果呢?

感谢。

5 个答案:

答案 0 :(得分:5)

如果你需要能够执行任意分割,听起来你需要一个有理数的表示(一个分数)。我不相信.NET默认提供一个,并且你会“有趣”地以与内置数字类型一样的方式实现它。这可能会让你进行加法,减法,乘法和除法 - 但如果你也需要无理数(例如取平方根),它就无济于事。

确定你将被除以3吗?你确定你不能舍入(比如)最接近的一分钱1000?您应该了解计算周围的精确要求是什么 - 我怀疑您确实需要无限精确。

答案 1 :(得分:4)

在处理金钱时,你不应该这样分开。您应该尽可能均匀地分配金额,从而获得分配列表,例如:

100 allocated by 3 = [ 33, 33, 34 ]

有人必须得到额外的一分钱。

此外,使用表示便士数的整数比使用十进制数更简单。

而且,封装货币操作是一个专门的类。看看Money pattern

答案 2 :(得分:3)

你能为我提供一个真实的用例示例吗?

mValue = mValue / 3

在三名银行劫匪之间划分 $ 100 ? 好吧,你不能给每个 $ 33。(3) $ 0.01 仍然必须“无处”(如果你不想让它们互相残杀)。

我只是这样说,因为钱不是数学,你需要确定所需的精度。
不多也不少。

答案 3 :(得分:2)

我不是这个领域的专家,所以有更多经验的人可能会更好地回答这个问题。

您可以非常安全地舍入到10000左右的分数,然后在您想要使用该号码时四舍五入到最近的便士。这适用于您发布的示例

100/3 = 33.333333333333333 * 3 = 99.99999999999,然后四舍五入为100.

我知道许多事情都使用了银行家的四舍五入。这是为了防止当事情以5结尾时赔钱。如果5之前的数字是奇数,则向上舍入,如果数字是偶数则向下舍入。需要考虑的事情。

http://en.wikipedia.org/wiki/Rounding

答案 4 :(得分:0)

重要的是为特定应用程序使用精确定义的舍入规则。如果结算应用程序指定所有订单项金额将四舍五入到最接近的便士,则发票总额应反映该结果。如果它指定所有计算都将执行到百分之一便士,那么发票应该反映出来(可能将小部分硬币格式化为上标,即天然气价格的方式)。在某些情况下,可以持续在发票项目中分配小数便士,例如

  old_total = total
  old_rounded_total = rounded_total
  total = total + line_item
  rounded_total = round_to_penny(total)
  displayed_line_item_cost = rounded_total - old_rounded_total

在其他情况下,可以将所有发票行四舍五入到最近的便士,从该总额中减去所有非圆形发票行的总和,并向上或向下调整最接近“便士”边界的那些行。 / p>

如果舍入语义定义明确,并且应用程序遵循它们,则结果将与规范精确匹配。如果语义没有明确定义,结果也不会。