public class Test
{
  public static void main(String[] args)
  {
  double x = 0.01;
  double y = 0.09;
  System.out.println(x + y);
  }
}为什么输出结果是0.09999999999999999而不是0.1啊?
奇怪的是当x,y改为float后,结果就等于0.1了,
更奇怪的是,如果把x,y分别改为float的0.01和0.04,在相加,结果居然是0.049999997,
这种浮点运算不精确的背后原理到底是什么呢?更加怪异的是,这段代码放到C#中运行,出来的结果却是0.1    class Test
    {
        static void Main()
        {
             double x = 0.01;
             double y = 0.09;
             Console.WriteLine(x + y);
             Console.ReadKey();
        }
    }

解决方案 »

  1.   

    JAVA的小数(浮点,DOUBLE)是会丢失精度的。要用精确计算就用BigDecimal
      

  2.   


             //java是一门很怪异的语言
    System.out.println(1.0/0);//Infinity
    System.out.println(1/0);// java.lang.ArithmeticException: 

      

  3.   

    这个很正常
    The details of proper input conversion from a Unicode string representation of a floating-point number to the internal IEEE 754 binary floating-point representation are described for the methods valueOf of class Float and class Double of the package java.lang.
    原因
      

  4.   

    第一点,你要明确java里面32位的float对0.1在内存当中的表示是不精确的,不是你理解的那么100%精确,抛弃这个概念,产生这个误差的原因简单理解在32位的float的表达能力有限和计算机的二进制缘故吧,往下说也很复杂。
    大体说下,float的0.1二进制形式是001111011 10011001100110011001101,根据符号位换算为10进制表达的值精确应该是这样计算 110011001100110011001101乘以2的负27次方,实际值是0.100000001490116119384765625
    这样就产生了实际误差
    这个误差对我们生活小打小闹没啥影响,但是对科学计算和银行这样的应用或者领域是致命的,因此要用Java银行以及科学计算会用java.math.BigDecimal提高精度,否则后果极其严重。参考我曾经回答过的CSDN帖子http://topic.csdn.net/u/20110804/00/15380122-33a1-474a-9b7f-3e90a000f0a8.html
      

  5.   

    这样也可以吧!
    public class DoubleClass{
    public static void main(String[] args){
    double x = 0.09;
    double y = 0.01;
    System.out.println((float)(x + y));
    }
    }
      

  6.   

    因为java 是不会表示1/10这个数值的,你可以使用bigdecimal这个类型试一下.
      

  7.   

    这个涉及到浮点数的结构(符号位,指数部分,尾数部分),以及规格化的表示和非规格化的表示。
    这里不详细解释,LZ可查阅相关资料
    有几个知识点:
      1.计算机中浮点数的基数是2.
      2.指数部分有偏移量(float为127, double为1023)
      3.规格化的表示小数点左边一定为1.(二进制数)
      4.float类型 符号位占1位,指数部分占8位,尾数占23位(因为规格化表示,小数点左边一定为1,所以实际有24位精度)
      5.double类型 符号位占1位,指数部分占11位,尾数占52位(因为规格化表示,小数点左边一定为1,所以实际有53位精度)看一个例子float 0.6吧:
    第一步,把十进制转2进制:
     0.6的二进制表示(乘2取整,顺序表示):
      .1001 1001 1001 1001 1001 1001 1001 ... 无限循环下去。第二步,计算尾数部分:
     把.1001 1001 1001 1001 1001 1001 1001 ...规格化表示(小数点移到第一个非0书右边)就是:
      1.001 1001 1001 1001 1001 1001 1001 ...,右移了1位。
     由于规格化表示的数小数点左边一定为1,把这个1舍弃,并保留float尾数能表示的23位,最终尾数部分是:
      001 1001 1001 1001 1001 1001第三步,计算指数部分: 
     由于计算尾数时右移了1位,相当于乘以2的负1次,所以指数为-1,加上float偏移量127,最后指数为126,
     二进制表示为 0111 1110第四步,符号部分:
     0.6为正数,符号位为0最终0.6在计算机中的表示就是: 符号位 指数 尾数
      0 0111 1110 001 1001 1001 1001 1001 1001
    --------------------------------------------------------------
    我们再从这个2进制来计算10进制数:(2的指数次 * 尾数)
     符号位0--> 为正
     指数 0111 1110:为126, 减去偏移量127,结果为-1.
     尾数 001 1001 1001 1001 1001 1001: 规格化的时候小数点左边人掉了一个1,现在加上:
      1.001 1001 1001 1001 1001 1001,转为10进制就是:
      1*2^0 + 1*2^-3 + 1*2^-4 + .....= 1.19999992847442626953125
    1.19999992847442626953125 * 2^-1 = 0.599999964237213134765625
    所以最终结果是一个无限接近于0.6而不能精确表示0.6 --------------------------------------
    其实我在这个帖子已经回复过了
      

  8.   

    我好奇的是为什么在C#中,浮点的运算看起来要比java中精确很多,如同LZ提到的例子,在C#中就是精确的1,当中是做了什么处理?java和C\C++一样,0.1多打印几位最后就会出现非0精度问题,C#中却一直都是精确的,为什么