黑马程序员技术交流社区

标题: 分析打印不出结果的原因 [打印本页]

作者: 冯佩    时间: 2013-2-17 12:27
标题: 分析打印不出结果的原因
本帖最后由 冯佩 于 2013-2-20 15:11 编辑

public class Test
{
     public static void main(String[] args)
     {
         double item = 1;
         double sum=0;
         while(item != 0)
         {
             sum += item;
             item -= 0.1;
          }
          System.out.println("sum="+sum);
      }
}
以上是对1+0.9+0.8+...+0.1进行求和的一种代码编写方式,请分析打印不出结果的原因。
作者: 王昕    时间: 2013-2-17 13:01
本帖最后由 王昕 于 2013-2-17 13:23 编辑

经过调试发现,-0.1之后,item就变成了0.90000000000000002,每步的结果都有误差,不是刚好减0.1,所以item一直都不等于0,所以一直循环。

作者: 燕国庆    时间: 2013-2-17 13:23
public class Test
{
     public static void main(String[] args)
     {
         double item = 1;
         double sum=0;
         while(item != 0)  //这段代码在河的时候出现了死循环,所以JVM无法执行输出语句 System.out.println("sum="+sum);

         {
             sum += item;
             item -= 0.1;
          }
          System.out.println("sum="+sum);
      }
}

作者: 张晋瑜    时间: 2013-2-17 13:26
因为这个循环永远不会结束
作者: 张晋瑜    时间: 2013-2-17 13:30
while(item != 0)
         {
             sum += item;
             item -= 0.1;
          }
由于你用的是double型数据,当item=0.8自减到0.7时得到的是item=0.7000000000000001       
你调试一下,会发现不会出现item=0.00000000000000的情况

作者: 康乐    时间: 2013-2-17 16:59
本帖最后由 康乐 于 2013-2-17 17:02 编辑

由于在-0.1时结果不够精确,所以出现了死循环。调试时会发现item在减了0.1几次以后结果就会不够精确。

java中floa或者double运算时可能会丢失精度,因为十进制小数转换成二进制数时表示可能不够精确,就像十进制系统中能不能准确表示出1/3,同样二进制系统也无法准确表示1/10。float和double只能用来做科学计算或者是工程计算,在精确的计算中我们要用java.math.BigDecimal。通常用的构造方法是以下两个:
BigDecimal(double val)
BigDecimal(String val)
第一个构造方法虽然用起来方便但是有一定的不可预知性,具体在API中有介绍
所以如果需要精确计算,最好用String来够造BigDecimal。
需要先将两个浮点数转为String,然后够造成BigDecimal,在其中一个上调用方法,传入另一个作为参数,
然后把运算的结果(BigDecimal)再转换为浮点数。

主函数总这样写
  1. double item = 1;
  2. double sum=0;
  3. while(item != 0)
  4. {
  5. sum += item;
  6. BigDecimal bdItem = new BigDecimal(Double.toString(item));
  7. BigDecimal bd = new BigDecimal("0.1");
  8. item = bdItem.subtract(bd).doubleValue();

  9. }
  10. System.out.println("sum="+sum);
复制代码

作者: 胥文    时间: 2013-2-17 22:01
public static void main(String[] args) {
               
                double temp =1;
                double sum = 0;
                while(temp !=0)
                {
                        sum+=temp;
                        temp = temp-0.1;
                        //使用给定的模式(小数保留一位)创建一个DecimalFormat对象
                        DecimalFormat df = new DecimalFormat(".0");
                        //将temp按照指定的格式格式化之后,在转化成Double
                        temp = Double.valueOf(df.format(temp));
                        System.out.println(temp);
                       
                }
               
                System.out.println(sum);

        }

}
已经验证,这样就是你要的结果
作者: 黄玉昆    时间: 2013-2-17 23:13
你试试这段代码,应该是没问题的了:
  1. public class Test
  2. {
  3.      public static void main(String[] args)
  4.      {
  5.          int item = 10;
  6.          float sum=0f;
  7.          while(item != 0)
  8.          {
  9.              sum += item;
  10.              item -= 1;
  11.           }
  12.           System.out.println("sum=" + (sum/10));
  13.       }
  14. }
复制代码
这里的float的范围要大于int,所以是可以进行sum+=item语句的。但是不能将sum定义为int,否则打印结果为int型了。
作者: 冯佩    时间: 2013-2-18 03:37
感谢各位的参与,在循环中请尽量不要使用浮点值来比较值是否相等,因为浮点值都是某些值的近似值,所以不能确保item会变成真正的0,从表面上看,这个循环似乎没问题,但实际上它是一个无限循环。
作者: 罗海清    时间: 2013-2-18 10:19
都很牛,楼主可以变成已解决了
作者: 铿锵科技    时间: 2013-2-18 12:51
       double item = 1;
         double sum=0;
         while(item != 0)
         {
             sum += item;
             item -= 0.1;
          }
          System.out.println("sum="+sum);
我是这样理解的:
java中switch()中不可使用浮点数来判断条件,同理while中也不会使用浮点数来判断条件,所以如果在while中判断条件的数值类型应该用整型




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2