真正的java的四舍五入

真正的java的四舍五入原文地址:https://blog.csdn.net/qwfylwc/article/details/53939906下面列举让你惊讶的现象,或许你还一直这么用:1、使用Math.round()doubled=1041.735;d=Math.round(d*100)/100.0;//除以100.0而不是100System.out.println(d);…

大家好,又见面了,我是你们的朋友全栈君。

原文地址:https://blog.csdn.net/qwfylwc/article/details/53939906

下面列举让你惊讶的现象,或许你还一直这么用:

1、使用Math.round()

  double d = 1041.735;
  d = Math.round(d*100)/100.0; //除以100.0 而不是100
  System.out.println(d); //输出结果是1041.73

2、使用 BigDecima

 double d = 9.655;
 BigDecimal b = new BigDecimal(d); 
 d = b.setScale(2,RoundingMode.HALF_UP).doubleValue();
 System.out.println(d); //输出结果是9.65

3、使用DecimalFormat

double d = 11.225;
DecimalFormat df = new DecimalFormat("0.00");
String s = df.format(d);
System.out.println(s);//输出结果是11.22

所有的根源都是double的浮点运算机制 
例1

1041.735*100=104173.49999999999
Math.round(1041.735*100)=104173

例2 
在进行使用double的构造函数之后,发生了变化,导致后续的四舍五入错误 
这里写图片描述

例3 
和例1、例2有点区别,在内部实现时,也是进行了相关的浮点预算

综上所述:只要进行浮点运算,就可能产生精度问题

上述例2和例3几乎接近真实,只需要进行一点调整即可 
例2

 double d = 9.655;
 //通过改变构造方法,就可以解决精度丢失问题
 BigDecimal b = new BigDecimal(Double.toString(d));
 d = b.setScale(2,RoundingMode.HALF_UP).doubleValue();
 System.out.println(d); //输出结果是9.66

例3

double d = 11.225;
DecimalFormat df = new DecimalFormat("0.00");
//指定RoundingMode 
df.setRoundingMode(RoundingMode.HALF_UP);
String s = df.format(d);
System.out.println(s);//输出结果是11.23

下面我们再来看一个经典的例子 
计算199999.00*0.015,结果保留2位有效数字 
理论上 199999.00*0.015=2999.985 
实际上java的bouble运算是 199999.00*0.015=2999.984999….

下面提供了一个double运算的工具类,最后的format解决了科学计数法显示问题(1.53E10)

public class DoubleUtil {
    private static final int DIV_SCALE=10;//默认除法运算精度 

    private DoubleUtil(){

    }

    /**
     * 提供精确的加法运算
     * @param v1 被加数
     * @param v2 加数
     * @return 两个参数的和
     */
    public static double add(double v1,double v2){
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.add(b2).doubleValue();
    }

    /**
     * 提供精确的减法运算
     * @param v1 被减数
     * @param v2 减数
     * @return 两个参数的差
     */
    public static double sub(double v1,double v2){
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.subtract(b2).doubleValue();
    }

    /**
     * 提供精确的乘法运算
     * @param v1 被乘数
     * @param v2 乘数
     * @return 两个参数的积
     */
    public static double mul(double v1,double v2){
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.multiply(b2).doubleValue();
    }

    /**
     * 提供(相对)精确的除法运算
     * 当除不尽时,使用默认精度:DIV_SCALE
     * @param v1 被除数
     * @param v2 除数
     * @return 两个参数的商
     */
    public static double div(double v1,double v2){
        return div(v1,v2,DIV_SCALE);
    }

    /**
     * 提供(相对)精确的除法运算
     * 当除不尽时,使用参数scale指定精度,进行四舍五入
     * @param v1 被除数
     * @param v2 除数
     * @param scale 表示精确到小数点后几位
     * @return 两个参数的商
     */
    public static double div(double v1,double v2,int scale){
        if(scale<0){
            throw new IllegalArgumentException("scale不能小于0");
        }
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.divide(b2,scale,BigDecimal.ROUND_HALF_UP).doubleValue();
    }

    /**
     * 提供精确的小数位四舍五入处理
     * @param v 需要四舍五入的数字 
     * @param scale 小数点后保留几位
     * @return 四舍五入后的结果
     */
    public static double round(double v1,int scale){

        if(scale<0){
            throw new IllegalArgumentException("scale不能小于0");
        }
        BigDecimal b = new BigDecimal(Double.toString(v1));
        BigDecimal one = new BigDecimal("1");
        return b.divide(one,scale,BigDecimal.ROUND_HALF_UP).doubleValue();
    }

    public static String format(double v1,int scale){

        String s = String.valueOf(round(v1,scale));
        s = new BigDecimal(s).toPlainString();//解决科学计算法转换问题

        int k = s.indexOf(".");
        if(k<0 && scale>0){
            s = s+".0";
            k=s.indexOf(".");
        }

        if(k>0){
            int d_scale = (s.length()-(k+1));
            if(scale>d_scale){
                for(int i=0;i<scale-d_scale;i++){
                    s+="0";
                }
            }else if(scale<d_scale){//当scale=0时才会出现这种情况
                s = s.substring(0,k);
            }
        }
        return s;
    }
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/156866.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • 鸿蒙 OS 2.0 来了!值得开发者关注的是什么?

    鸿蒙 OS 2.0 来了!值得开发者关注的是什么?鸿蒙OS首发时,余承东特意用橙色标明1.0版本「基于开源框架,关键模块自研」。而按照华为的规划,今年在HDC上刚刚发布的鸿蒙2.0迎来了史诗级升级,完全演化成一个自主独立的操作系统。

  • STM32移植LWIP

    STM32移植LWIP本文使用的是STM32F207VCT6平台,MII接口的RTL8201EL网络芯片,LWIP版本是1.4.1基础工程是:已经实现了10ms定时,led灯1s闪烁,还有串口打印欢迎查看本文所在的系列,STM32的LWIP应用,点击跳转本文使用的IDE是IAR7.2,考虑到很多很使用Keil,本文末尾也有keil版本的说明添加以太网驱动库添加进工程,增加新库的头文件路径将LWIP源码放入目录中我们把s…

  • 路由器VLAN对接交换机VLAN_交换机vlan指的是什么

    路由器VLAN对接交换机VLAN_交换机vlan指的是什么**浅谈路由器,交换机,集线器,vlan作用**二层交换机:基于MAC有MAC单播无MAC洪泛路由器的作用:1.路由(为其所承载的数据路由)—选路2.不同步广播域隔离广播域3.不同网络类型通讯交换机的作用:1.取代集线器2.也提供接口连接更多的用户3.基于MAC地址单播通讯4.理论上无限延长传输距离5.对二进制进行存储存储数据集线器(一层设备物理层…

  • 【数据库】count(*),count(1)和count(列)

    【数据库】count(*),count(1)和count(列)【数据库】count(*),count(1)和count(列)

  • 基于java的项目开发过程_软件开发项目管理整个流程图

    基于java的项目开发过程_软件开发项目管理整个流程图完整项目开发过程原型的设计有产品经理负责。界面的美化有专门的美工负责。前端有专门的前端开发人员负责。研发:研发主要工作就是根据项目的需求文档设计系统架构、设计数据库、编写调试程序代码。对于普通的码农来说,主要的就是编写和调试程序。基于Java的项目开发:1、要想编写程序,需要一个能编写源代码的编辑工具。例如:Notepad++;2、要想测试程序,需要一个编译、执行

    2022年10月26日
  • utf-8的中文是一个汉字占三个字节长度吗?

    utf-8的中文是一个汉字占三个字节长度吗?英文字母和中文汉字在不同字符集编码下的字节数英文字母:字节数:1;编码:GB2312字节数:1;编码:GBK字节数:1;编码:GB18030字节数:1;编码:ISO-8859-1字节数:1;编码:UTF-8字节数:4;编码:UTF-16字节数:2;编码:UTF-16BE字节数:2;编码:UTF-16LE中文汉字:字节数:2;编码:GB2312字节数:2;编…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号