C# .NET 中的双乘法被破坏了吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1420752/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 16:20:55  来源:igfitidea点击:

Is double Multiplication Broken in .NET?

c#.netmath

提问by Dan

If I execute the following expression in C#:

如果我在 C# 中执行以下表达式:

double i = 10*0.69;

iis: 6.8999999999999995. Why?

i是:6.8999999999999995。为什么?

I understand numbers such as 1/3 can be hard to represent in binary as it has infinite recurring decimal places but this is not the case for 0.69. And 0.69 can easily be represented in binary, one binary number for 69 and another to denote the position of the decimal place.

我知道像 1/3 这样的数字很难用二进制表示,因为它有无限重复的小数位,但 0.69 的情况并非如此。0.69 可以很容易地用二进制表示,一个二进制数表示 69,另一个表示小数点的位置。

How do I work around this? Use the decimaltype?

我该如何解决这个问题?使用decimal类型?

采纳答案by Jon Skeet

Because you've misunderstood floating point arithmetic and how data is stored.

因为您误解了浮点运算以及数据的存储方式。

In fact, your code isn't actually performing any arithmetic at execution time in this particular case - the compilerwill have done it, then saved a constant in the generated executable. However, it can'tstore an exact value of 6.9, because that value cannot be precisely represented in floating point point format, just like 1/3 can't be precisely stored in a finite decimal representation.

事实上,在这种特殊情况下,您的代码实际上并没有在执行时执行任何算术 -编译器会完成它,然后在生成的可执行文件中保存一个常量。但是,它无法存储 6.9 的精确值,因为该值无法以浮点格式精确表示,就像 1/3 无法以有限十进制表示形式精确存储一样。

See if this articlehelps you.

看看这篇文章是否对你有帮助。

回答by erikkallen

For the same reason that 1 / 3 in a decimal systems comes out as 0.3333333333333333333333333333333333333333333 and not the exact fraction, which is infinitely long.

出于同样的原因,十进制系统中的 1 / 3 是 0.33333333333333333333333333333333333333333333,而不是无限长的精确分数。

回答by Russell Steen

why doesn't the framework work around this and hide this problem from me and give me the right answer,0.69!!!

为什么框架不解决这个问题并向我隐藏这个问题并给我正确的答案,0.69!!!

Stop behaving like a dilbert manager, and accept that computers, though cool and awesome, have limits. In your specific case, it doesn't just "hide" the problem, because you have specifically told it not to. The language (the computer) provides alternatives to the format, that you didn't choose. You chose double, which has certain advantages over decimal, and certain downsides. Now, knowing the answer, you're upset that the downsides don't magically disappear.

不要表现得像一个呆板的经理,接受计算机虽然很酷很了不起,但也有局限性。在您的具体情况下,它不仅仅是“隐藏”问题,因为您已经明确告诉它不要这样做。语言(计算机)提供了您没有选择的格式的替代方案。你选择了 double,它比十进制有一定的优势,但也有一定的缺点。现在,知道答案后,您对缺点并没有神奇地消失感到沮丧。

As a programmer, you are responsible for hiding this downside from managers, and there are many ways to do that. However, the makers of C# have a responsibility to make floating point work correctly, and correct floating point will occasionally result in incorrect math.

作为一名程序员,你有责任向经理隐瞒这个缺点,有很多方法可以做到这一点。但是,C# 的创造者有责任让浮点数正确工作,正确的浮点数偶尔会导致不正确的数学运算。

So will every other number storage method, as we do not have infinite bits. Our job as programmers is to work with limited resources to make cool things happen. They got you 90% of the way there, just get the torch home.

所有其他数字存储方法也是如此,因为我们没有无限位。作为程序员,我们的工作是利用有限的资源来完成很酷的事情。他们已经完成了 90% 的工作,只需将火炬带回家即可。

回答by Clifford

but why doesn't the framework work around this and hide this problem from me and give me the right answer,0.69!!!

但是为什么框架没有解决这个问题并向我隐藏这个问题并给我正确的答案,0.69!!!

Because you told it to use binary floating point, and the solution is to use decimal floating point, so you are suggesting that the framework should disregard the type you specified and use decimalinstead, which is very much slower because it is not directly implemented in hardware.

因为你告诉它使用二进制浮点数,而解决方案是使用十进制浮点数,所以你建议框架应该忽略你指定的类型并使用十进制代替,这非常慢,因为它没有直接在硬件。

A more efficient solution is to not output the full value of the representation and explicitly specify the accuracy required by your output. If you format the output to two decimal places, you will see the result you expect. However if this is a financial application decimalis precisely what you should use - you've seen Superman III (and Office Space) haven't you ;)

更有效的解决方案是不输出表示的完整值,并明确指定输出所需的精度。如果您将输出格式化为两位小数,您将看到您期望的结果。但是,如果这是一个金融应用程序,十进制正是您应该使用的 - 您已经看到了超人 III(和办公空间),不是吗;)

Note that it is all a finite approximation of an infinite range, it is merely that decimaland doubleuse a different set of approximations. The advantage of decimalis it produces the same approximations that you would if you were performing the calculation yourself. For example if you calculated 1/3, you would eventually stop writing 3's when it was 'good enough'.

请注意,这都是无限范围的有限近似值,只是小数精度使用不同的近似值集。小数的优点是它产生的近似值与您自己执行计算时产生的近似值相同。例如,如果你计算了 1/3,当它“足够好”时,你最终会停止写 3。

回答by Keith

And 0.69 can easily be represented in binary, one binary number for 69 and another to denote the position of the decimalplace.

0.69 可以很容易地用二进制表示,一个二进制数表示 69,另一个表示 小数点的位置。

I think this is a common mistake - you're thinking of floating point numbers as if they are base-10 (i.e decimal - hence my emphasis).

我认为这是一个常见的错误-您将浮点数视为基数为 10(即十进制数-因此我的重点)。

So - you're thinking that there are two whole-number parts to this double: 69and divide by 100to get the decimal place to move - which could also be expressed as:
69 x 10 to the power of -2.

所以 - 你认为这个 double 有两个整数部分:69除以 100来移动小数位 - 这也可以表示为:
69 x 10 的 -2 次方

However floats store the 'position of the point' as base-2.

然而,浮点数将“点的位置”存储为base-2

Your float actually gets stored as:
68999999999999995 x 2 to the power of some big negative number

您的浮点数实际上存储为:
68999999999999995 x 2 的某个大负数的幂

This isn't as much of a problem once you're used to it - most people know and expect that 1/3 can't be expressed accurately as a decimal or percentage. It's just that the fractions that can't be expressed in base-2 are different.

一旦你习惯了,这不是什么大问题——大多数人都知道并期望 1/3 不能准确地表示为小数或百分比。只是不能用base-2表示的分数不同而已。

回答by Richard

To work around it (e.g. to display on screen) try this:

要解决它(例如在屏幕上显示),请尝试以下操作:

double i = (double) Decimal.Multiply(10, (Decimal) 0.69);

Everyone seems to have answered your first question, but ignored the second part.

好像大家都回答了你的第一个问题,但是忽略了第二部分。