关于c#:浮点运算模糊

Floating point operations ambiguity

本问题已经有最佳答案,请猛点这里访问。

Possible Duplicate:
Why is floating point arithmetic in C# imprecise?

为什么浮点运算存在偏差?有什么具体原因吗?输出:一百六十一百三十九

1
2
3
4
5
6
7
8
9
10
static void Main()
        {
            float x = (float) 1.6;
            int y = (int)(x * 100);
            float a = (float) 1.4;
            int b = (int)(a * 100);
            Console.WriteLine(y);
            Console.WriteLine(b);
            Console.ReadKey();
        }


任何有理数的分母不是2的幂,当用二进制表示时,都会导致无穷多的数字。这里有8/5和7/5。因此,没有确切的二进制表示形式作为浮点数(除非您有无限的内存)。

1.6的精确二进制表示是110011001100110011001100110011001100…1.4的精确二进制表示是1011001100110011001100110011001100110011…两个值的位数都是无限的(1100是无限重复的)。

浮点值的精度为24位。因此,任何值的二进制表示都将四舍五入为24位。如果将给定值四舍五入为24位,则得到:1.6:11001100110011001101(十进制13421773)-向上取整1.4:101100110011001100110011(十进制11744051)-四舍五入

两个值的指数均为0(第一位为2^0=1,第二位为2^-1=0.5等)。因为24位值中的第一位是2^23,所以可以通过将24位值(13421773和11744051)除以2 23次来计算精确的十进制值。数值为:1.60000002384185791015625和1.399999976158141208984375。

使用浮点类型时,必须始终考虑其精度是有限的。可以精确写入十进制值的值在表示为二进制时可能向上或向下取整。强制转换为int并不考虑这一点,因为它会截断给定的值。你应该总是使用类似math.round的东西。

如果你真的需要一个有理数的精确表示,你需要一个完全不同的方法。因为有理数是分数,所以可以使用整数来表示它们。下面是一个如何实现这一目标的例子。但是,您不能编写Rational X=(Rational)1.6。你必须写一些东西,比如RationalX=New Rational(8,5)(或者New Rational(16,10)等等)。


这是因为浮点运算不精确。当您将a设置为1.4时,内部可能不完全是1.4,就像机器精度所能达到的那样。如果其分数小于1.4,则乘以100并转换为整数将只取整数部分,在本例中为139。你会得到更精确的技术答案,但本质上这就是正在发生的事情。

在输出1.6的情况下,浮点表示实际上可能比1.6小,因此当乘以100时,总数略大于160,因此整数转换给出了您所期望的结果。事实上,在计算机中,没有足够的精度来精确存储每一个实数。

有关从浮点到整数类型的转换的详细信息,请参阅此链接http://msdn.microsoft.com/en-us/library/aa691289%28v=vs.71%29.aspx-它有自己的部分。


浮点类型float(32位)和double(64位)的精度有限,超过该值的部分在内部表示为二进制值。正如在十进制系统中不能精确地表示1/7(~0.1428571428571428…),1/10不能在二进制系统中精确地表示。

但是,您可以使用decimal类型。它的精度仍然有限(但很高),但数字A在内部以十进制方式表示。因此,1/10这样的值在内部的表示方式与0.10000000000000000000000000完全相同。1/7仍然是decimal的一个问题。但至少你不会因为转换成二进制然后再转换回十进制而损失精度。

考虑使用decimal