C# 双重乘法在.NET中被打破了吗?

C# 双重乘法在.NET中被打破了吗?,c#,.net,math,C#,.net,Math,如果我在C#中执行以下表达式: i是:6.899999999995。为什么? 我知道像1/3这样的数字很难用二进制表示,因为它有无限个循环小数位数,但0.69就不是这样了。0.69可以很容易地用二进制表示,一个二进制数表示69,另一个表示小数点的位置 我如何解决这个问题?使用十进制类型?,因为您误解了浮点运算和数据的存储方式 事实上,在这种特殊情况下,您的代码在执行时并没有实际执行任何算术运算——编译器将完成此操作,然后在生成的可执行文件中保存一个常量。但是,它不能存储6.9的精确值,因为该值不

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

i
是:
6.899999999995
。为什么?

我知道像1/3这样的数字很难用二进制表示,因为它有无限个循环小数位数,但0.69就不是这样了。0.69可以很容易地用二进制表示,一个二进制数表示69,另一个表示小数点的位置


我如何解决这个问题?使用十进制类型?

,因为您误解了浮点运算和数据的存储方式

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


看看是否对你有帮助。

原因与十进制中的1/3表示为0.3333333,而不是确切的分数,它是无限长的

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

别再表现得像个迪尔伯特经理了,承认电脑虽然酷又酷,但也有局限性。在您的特定情况下,它不仅仅是“隐藏”问题,因为您已经明确告诉它不要这样做。语言(计算机)提供了格式的替代方案,而不是您选择的。您选择了double,它比decimal有一些优点,但也有一些缺点。现在,知道了答案,你会为负面影响没有神奇地消失而难过

作为一名程序员,你有责任向管理者隐瞒这个缺点,有很多方法可以做到这一点。然而,C#的制造商有责任使浮点正确工作,正确的浮点有时会导致错误的数学

其他数字存储方法也是如此,因为我们没有无限位。作为程序员,我们的工作就是利用有限的资源来完成一些很酷的事情。他们把你带到了90%的地方,只要把火炬带回家就行了

但是为什么框架不能解决这个问题,对我隐藏这个问题,给我一个正确的答案,0.69

因为您告诉它使用二进制浮点,而解决方案是使用十进制浮点,所以您建议框架应该忽略您指定的类型,而使用十进制,这非常慢,因为它不是直接在硬件中实现的

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

请注意,这都是一个无限范围的有限近似值,只是十进制和双精度使用了一组不同的近似值。decimal的优点是,它产生的近似值与您自己进行计算时的近似值相同。例如,如果你计算1/3,你最终会在“足够好”的时候停止写3

0.69可以很容易地表示为 二进制,一个二进制数表示69和 另一个用于表示 小数位

我认为这是一个常见的错误-你认为浮点数就像它们是以10为基数(即十进制-因此我强调)

所以-你认为这个双精度有两个整数部分:69除以100得到小数点-也可以表示为:
69 x 10到-2的幂次方

但是,浮动将“点的位置”存储为base-2

您的浮动实际上存储为:

68999999995 x 2乘以某个大负数的幂

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

要解决这个问题(例如在屏幕上显示),请尝试以下方法:

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

每个人似乎都回答了你的第一个问题,但是忽略了第二部分。

请考虑一下:在一个已经存在了很多年的框架中,你碰巧遇到这样一个bug的几率是多少?在几乎正确地实现浮点运算的任何其他语言/框架中,你都会得到类似的结果。这是一个不变的真理;任何时候你读到一个带有“。。。在abc语言中,乘法被破坏了关于浮点:)布莱恩:我认为这不是一个好方法。我认为你可以合理地假设可能存在问题,但我也认为自己研究它是合理的。回到那一天,我记得我发现了Java bug;这并不意味着我很特别,这只是个意外。研究是需要教授的。我喜欢如何解释如何将其存储在二进制中取决于指定小数点后的isI可能显示我的天真,但为什么框架不能解决这个问题,向我隐藏这个问题,并给我正确的答案,0.69@丹:因为你的意思可能不是0.69。您可能指的是由相同位模式表示的其他许多值中的任何一个。如果要表示本质上是十进制的值,应首先使用
decimal
类型。请注意,在这里选择“输出”是解决如何将特定类型的实例转换为文本格式的问题。。。这与决定在应用程序中使用哪种类型有些不同
double i = (double) Decimal.Multiply(10, (Decimal) 0.69);