在C#中使用float计算财务价值的问题

时间:2015-06-05 05:54:55

标签: c# discount

我正在阅读一篇与Float和double之间的区别有关的文章。他们给出了一个例子如下:

假设您有100美元的商品,并且您可享受10%的折扣。您的价格都是全部美元,因此您使用int变量来存储价格。这是你得到的:

int fullPrice = 100;
float discount = 0.1F;
Int32 finalPrice = (int)(fullPrice * (1-discount));
Console.WriteLine("The discounted price is ${0}.", finalPrice);

猜猜:最终价格是89美元,而不是预期的90美元。您的客户会很高兴,但您不会。您已经给了他们1%的额外折扣。

在上面的示例中,要计算他们使用的最终价格fullPrice * (1-discount)。为什么他们使用(1-disocunt)?它应该是fullPrice * discount

所以我的困惑是关于计算最终价格的逻辑。为什么使用(1-discount)代替discount

3 个答案:

答案 0 :(得分:1)

  

最终价格是89美元,而不是预期的90美元

那是因为当0.1float时,它不完全是0.1,而是更多一点。当你从1中减去它来进行数学运算时,得到$89.9999998509884。转换为int会将结果截断为89demo)。

您可以使用decimal数据类型进行折扣。此类型可以表示0.1而没有精度损失(demo)。

  

为什么他们使用(1-disocunt)

1代表100%。折扣后的价格是(100%-10%)= 90%

答案 1 :(得分:0)

这个问题实际上是关于数学的。

我们建议您购买一件价值100美元的商品 卖家为您提供折扣 - 10%。

现在您需要计算物品的最终价格。 即,你应该花多少钱才能得到它?

答案:您需要支付商品的全价减去折扣价 100%的成本 - 10%的折扣= 90%的最终价格

这就是fullPrice * (1 - discount)的原因 如果您使用公式fullPrice * discount进行计算,则意味着100美元的商品将因10%的折扣而以10美元的价格出售 - 这是不正确的。实际上,此公式{​​{1}}可用于计算折扣金额。

答案 2 :(得分:0)

上述示例的整体逻辑没有任何问题,但它确实有非常不幸的数据类型选择。这导致值被隐式转换为double,在过程中引入了轻微的舍入误差。通过强制转换为int,结果将被截断。这极大地放大了舍入误差。

这是在编程中处理财务价值时经常出现的问题的一个很好的例子:

浮动值不能很好地反映小数

大多数新开发人员倾向于将浮点值视为小数,因为当将它们转换为字符串时,它们主要由这些表示,反之亦然。 情况并非如此。 Float值的小数部分存储为二进制分数,如同here所示。

这使浮点值(及其计算)从它们的十进制表示略微偏斜。这就是为什么以下结果为$ 89,9999998509884:

double fullPrice = 100;
double discount = 0.1F;
double finalPrice = (fullPrice * (1 - discount));
Console.WriteLine("The discounted price is ${0}.", finalPrice);

(不是那样)有趣的事实:当使用float作为数据类型时,上面的工作正常,因为在这个例子中,所提到的错误低于单精度值的分辨率,并且汇编代码确实使用了后面的双精度场景。当结果转换为单精度时,错误就会丢失。

解决这个问题的另一种方法是使用数据类型decimal,它被构造为进行必须直接转换为小数部分的计算(如财务计算所做的那样):

decimal fullPrice = 100;
decimal discount = 0.1m;
decimal finalPrice = (fullPrice * (1 - discount));
Console.WriteLine("The discounted price is ${0}.", finalPrice);

另一种方法是在显示或存储浮点计算之前对其进行舍入。对于财务计算,一个人应该使用:

Math.Round([your value here], 2, MidpointRounding.AwayFromZero);