C# 数学给出错误结果!

发布于 2024-10-20 09:02:58 字数 463 浏览 2 评论 0原文

我理解这个问题背后的原理,但想到这种情况在我的应用程序中发生并且我需要找到解决方案,这让我很头痛。

double Value = 141.1;
double Discount = 25.0;
double disc = Value * Discount / 100; // disc = 35.275
Value -= disc; // Value = 105.824999999999999

Value = Functions.Round(Value, 2); // Value = 105.82

我使用双精度数来表示相当小的数字。不知何故,在计算 141.1 - 35.275 时,结果的二进制表示给出的数字仅为 0.0000000000001。不幸的是,由于我随后对这个数字进行四舍五入,因此给出了错误的答案。

我读过有关使用小数而不是双精度的内容,但我无法用小数替换双精度的每个实例。有没有更简单的方法来解决这个问题?

I understand the principle behind this problem but it's giving me a headache to think that this is going on throughout my application and I need to find as solution.

double Value = 141.1;
double Discount = 25.0;
double disc = Value * Discount / 100; // disc = 35.275
Value -= disc; // Value = 105.824999999999999

Value = Functions.Round(Value, 2); // Value = 105.82

I'm using doubles to represent quite small numbers. Somehow in the calculation 141.1 - 35.275 the binary representation of the result gives a number which is just 0.0000000000001 out. Unfortunately, since I am then rounding this number, this gives the wrong answer.

I've read about using Decimals instead of Doubles but I can't replace every instance of a Double with a Decimal. Is there some easier way to get around this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

只是我以为 2024-10-27 09:02:58

如果您正在寻找自然十进制值的精确表示,则需要将所有位置的 double 替换为 decimal。您只是使用了错误的数据类型。如果您一直在整数中使用 short,然后发现您需要处理比支持的更大的值,您会怎么做?这是同样的交易。

但是,您确实应该尝试了解正在发生的事情……例如,为什么 Value 不完全等于 141.1。

文章:

If you're looking for exact representations of values which are naturally decimal, you will need to replace double with decimal everywhere. You're simply using the wrong datatype. If you'd been using short everywhere for integers and then found out that you needed to cope with larger values than that supports, what would you do? It's the same deal.

However, you should really try to understand what's going on to start with... why Value doesn't equal exactly 141.1, for example.

I have two articles on this:

她说她爱他 2024-10-27 09:02:58

您应该使用十进制——这就是它的用途。

浮点运算的行为?这就是它的作用。它的精度有限。并非所有数字都可以精确表示。事实上,实值数有无数个,但只能表示有限个数。对于此应用程序,decimal 的关键在于它使用基数 10 表示 - double 使用基数 2。

You should use decimal – that's what it's for.

The behaviour of floating point arithmetic? That's just what it does. It has limited finite precision. Not all numbers are exactly representable. In fact, there are an infinite number of real valued numbers, and only a finite number can be representable. The key to decimal, for this application, is that it uses a base 10 representation – double uses base 2.

好倦 2024-10-27 09:02:58

您可以使用自己编写的一些函数,而不是使用 Round 来对数字进行舍入,该函数在舍入时使用一个小 epsilon 以允许错误。这就是你想要的答案。

你不想要的答案,但无论如何我要给出的是,如果你想要精度,并且由于你正在处理金钱,从你的例子来看你可能会这样做,你不应该使用二进制浮点数学。二进制浮点本质上是不准确的,并且某些数字无法正确表示。使用 Decimal(以 10 为基数进行浮点运算)在任何地方都是一种更好的方法,并且可以避免您在双打方面犯下代价高昂的错误。

Instead of using Round to round the number, you could use some function you write yourself which uses a small epsilon when rounding to allow for the error. That's the answer you want.

The answer you don't want, but I'm going to give anyway, is that if you want precision, and since you're dealing with money judging by your example you probably do, you should not be using binary floating point maths. Binary floating point is inherently inaccurate and some numbers just can't be represented correctly. Using Decimal, which does base-10 floating point, would be a much better approach everywhere and will avoid you making costly mistakes with your doubles.

指尖微凉心微凉 2024-10-27 09:02:58

在花了早上的大部分时间尝试将“双精度”的每个实例替换为“十进制”并意识到我正在打一场失败的战斗之后,我再次审视了我的 Round 函数。这对于那些无法实现正确解决方案的人可能很有用:

public static double Round(double dbl, int decimals) {            
        return (double)Math.Round((decimal)dbl, decimals, MidpointRounding.AwayFromZero);
    }

首先将值转换为小数,然后调用 Math.Round,这将返回“正确”值。

After spending most of the morning trying to replace every instance of a 'double' to 'decimal' and realising I was fighting a losing battle, I had another look at my Round function. This may be useful to those who can't implement the proper solution:

public static double Round(double dbl, int decimals) {            
        return (double)Math.Round((decimal)dbl, decimals, MidpointRounding.AwayFromZero);
    }

By first casting the value to a decimal, and then calling Math.Round, this will return the 'correct' value.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文