美文网首页
一串数字什么鬼?java中float类型计算不精确

一串数字什么鬼?java中float类型计算不精确

作者: 隋胖胖LoveFat | 来源:发表于2016-01-08 17:15 被阅读1026次

一、写java小程序的时候碰到的奇怪事儿

今天同学让帮忙给她解决一个数学迭代问题,题目很简单,写代码用个循环就可以计算出结果。核心的java代码最开始如下:

float priceBefore=1.0f;   float priceNow = 1.0f;
for(int i = 1;i<10000;i++){
            priceNow = priceNow + 0.02f;
            System.out.println("第"+i+"天,大米的价格是:"+priceNow+"  要大于"+priceBefore*1.05+"才可以卖的哦");
            if(priceNow>priceBefore*1.05){
                System.out.println("第"+i+"天,大米可以卖啦");
                priceBefore = priceNow;
                price.add(priceNow);
                priceTime.add(i);
                int canSell = (int) (sell*0.05);
                sell = sell - canSell;
                sum = sum+canSell;
                if(sum*priceNow>10000){
                    System.out.println("第"+i+"天,大米价格是:"+priceNow+",可卖大米"+sum+"斤,赚:"+sum*priceNow+"元钱!");
                    break;
                }
            }   

我们看到代码的输出是:

第1天,大米的价格是:1.02 要大于1.05才可以卖的哦
第2天,大米的价格是:1.04 要大于1.05才可以卖的哦
第3天,大米的价格是:1.06 要大于1.05才可以卖的哦
第3天,大米可以卖啦
第3天,可卖大米500
第4天,大米的价格是:1.0799999 要大于1.1129999399185182才可以卖的哦
第5天,大米的价格是:1.0999999 要大于1.1129999399185182才可以卖的哦
第6天,大米的价格是:1.1199999 要大于1.1129999399185182才可以卖的哦
第6天,大米可以卖啦
...

我们看到奇怪的到循环第四次的时候,出现了1.0799999这样一连串数字,按照代码逻辑这时参数的结果应该是1.08才对!这对于我这个强迫症患者来说绝对不能容忍,虽说差别只是0.0000001,但是总感觉不是很准确。


二、这是float类型计算不精确搞的鬼

《Effective Java》中已经讲出了这种问题,float/double不能停供完全精确的计算结果。这个原理其实很简单,float/int都是32bit(也就是一共有2^32个精确值),而int的范围是-2^31 ~ 2^31-1,而Float的最大值是3.4028235e+38,远大于2^31 - 1。而且,int只负责个数有限的整数,而浮点却要用来表示个数无穷的小数,显然力不从心。浮点精确值可以简单视作一个以0为中心的正态分布,绝对值越小(越接近0的地方),相邻两个精确值月密集。比如,最近的两个值可能只相差0.00000...几十个0...01,而最远的两个精确值,却差了2.028241E31。


三、如何解决float类型计算不精确的问题

已经封装好的工具包java.math.BigDecimal可以帮助我们完美地解决float/double类型计算不精确的问题。与浮点不同,它可以提供精度任意(当然在硬件限制范围内)的计算结果,但是,只能进行四则运算或者基于四则运算的其他简单运算。
重新修改我的代码:

 float priceBefore=1.0f;    float priceNow = 1.0f;
 for(int i = 1;i<10000;i++){
            BigDecimal temp = new BigDecimal(Float.toString(priceNow));
            BigDecimal add = new BigDecimal(Float.toString(0.02f));
            priceNow=temp.add(add).floatValue();
            BigDecimal priceBeforeTemp = new BigDecimal(Float.toString(priceBefore));
            BigDecimal multi = new BigDecimal(Float.toString(1.05f));
            float priceThrold = priceBeforeTemp.multiply(multi).floatValue();
            System.out.println("第"+i+"天,大米的价格是:"+priceNow+"  要大于"+priceThrold+"才可以卖的哦");
            if(priceNow>priceThrold){
                System.out.println("第"+i+"天,大米可以卖啦");
                priceBefore = priceNow;
                price.add(priceNow);
                priceTime.add(i);
                int canSell = (int) (sell*0.05);
                sell = sell - canSell;
                sum = sum+canSell;
                if(sum*priceNow>10000){
                    System.out.println("第"+i+"天,大米价格是:"+priceNow+",可卖大米"+sum+"斤,赚:"+sum*priceNow+"元钱!");
                    break;
                }
            }           

我们看到关键代码行

BigDecimal temp = new BigDecimal(Float.toString(priceNow));
BigDecimal add = new BigDecimal(Float.toString(0.02f));
priceNow=temp.add(add).floatValue();

以及:

BigDecimal priceBeforeTemp = new BigDecimal(Float.toString(priceBefore));
BigDecimal multi = new BigDecimal(Float.toString(1.05f));
float priceThrold = priceBeforeTemp.multiply(multi).floatValue();

就是利用BigDecimal对float类型数据分别进行加法以及乘法运算。
这时候我们再来看输出:

第1天,大米的价格是:1.02 要大于1.05才可以卖的哦
第2天,大米的价格是:1.04 要大于1.05才可以卖的哦
第3天,大米的价格是:1.06 要大于1.05才可以卖的哦
第3天,大米可以卖啦
第4天,大米的价格是:1.08 要大于1.113才可以卖的哦
第5天,大米的价格是:1.1 要大于1.113才可以卖的哦
第6天,大米的价格是:1.12 要大于1.113才可以卖的哦
第6天,大米可以卖啦

完美!

相关文章

  • 一串数字什么鬼?java中float类型计算不精确

    一、写java小程序的时候碰到的奇怪事儿 今天同学让帮忙给她解决一个数学迭代问题,题目很简单,写代码用个循环就可以...

  • iOS float double 类型计算不精确

    因为做的商城项目需要计算钱数,以前一直用的float类型相加,但是对照发现小数点后面有误差,俩位小数点相加变成了三...

  • java每日一问

    Q: float类型在Java中占用4字节,long类型在Java中占用8字节,为什么float类型的取值范围比l...

  • Java语言中:float、double在内存中存储方式

    java语言中,float类型数字在计算机中用4个字节(32位)来存储。double类型占用8个字节(64位)。 ...

  • Python learning

    Python learning 编码 计算 Python 支持的数字类型有:int、float、Decimal(十...

  • Js数据类型

    1、Number   Java的"数字类型"分为int、float、double、long等,但是在Js中,统一用...

  • javaSE学习-方法的重载

    问题 之前已经写了一个方法sumInt用来计算两个int类型数字的和,如果要是想计算两个float类型数字的和呢?...

  • 金额为什么不用Float类型

    在软件开发中,老鸟程序员常常告诫新鸟程序员,金额不要用Float类型,因为Float不精确,会产生误差,涉及到钱可...

  • 方法的重载(overload)

    问题之前已经写了一个方法sumInt用来计算两个int类型数字的和,如果要是想计算两个float类型数字的和呢?o...

  • Python基础

    Python中的数据类型:Number(数字类型) int float boole 复数类型S...

网友评论

      本文标题:一串数字什么鬼?java中float类型计算不精确

      本文链接:https://www.haomeiwen.com/subject/biifkttx.html