前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >数字的陷阱

数字的陷阱

作者头像
java达人
发布2018-02-01 14:10:37
7830
发布2018-02-01 14:10:37
举报
文章被收录于专栏:java达人

Java中对数字的处理,如四舍五入,如加减乘除,貌似是一个很基础很简单的知识点,但是如果你没有对他进行充分了解,很容易掉进它的陷阱里。

1、浮点数运算

先来看一个对浮点数作运算的例子,请问会输出什么:

System.out.println(4.015*100);

结果可能会让你大跌眼镜,不是401.5,而是401.49999999999994,这就要涉及到浮点数的一些知识点,Java中,浮点类型是依据IEEE754标准,IEEE754定义了32位和64位双精度两种浮点二进制小数标准,而采用二进制表示double,float浮点数是不准确的(可点击阅读原文了解详情),如果想获得准确的结果,可以使用BigDecimal类:

System.out.println(new BigDecimal("4.015").multiply(new BigDecimal("100")).doubleValue());

System.out.println(BigDecimal.valueOf(4.015).multiply(BigDecimal.valueOf(100)).doubleValue());

以上输出结果都是401.5,如果你觉得到此已经避开了精度缺失的陷阱,那就再看下面这个例子:

System.out.println(new BigDecimal(0.1));

//result:0.1000000000000000055511151231257827021181583404541015625

这个构造器BigDecimal(double val)的结果是不可预知的,这里,0.1无法准确地表示为 double类型(一个有限长度的二进制小数),传入到构造方法的参数值并不完全等于 0.1。而BigDecimal(String val)的结果则是可预知的,所以我们一般优先使用BigDecimal(String val)型的构造函数。

2、四舍五入

再来瞅瞅四舍五入,或许你觉得以下代码貌似可行:

DecimalFormat df = new DecimalFormat("#.000");

System.out.println(df.format(203.0675));

//203.068

我们换一个数字看看:

DecimalFormat df = new DecimalFormat("#.000");

System.out.println(df.format(203.0665));

//203.066

奇怪不,四舍五入的规则换一个数字怎么就失效了呢,如果你研究过java中RoundingMode,你就会猜到它默认使用的是RoundingMode.HALF_EVEN,即如果舍弃部分左边的数字为奇数,则舍入行为同 RoundingMode.HALF_UP;如果为偶数,则舍入行为同RoundingMode.HALF_DOWN,这是银行家舍入法,在美国比较流行。那我们重新设置下模式就可以了。

DecimalFormat df = new DecimalFormat("#.000");

df.setRoundingMode(RoundingMode.HALF_UP);

System.out.println(df.format(203.0665));

//203.067

关于四舍五入,还有很多方法,请思考以下方法。

(1)、System.out.println(String.format("%.3f", 203.6665));

(2)、System.out.println(new BigDecimal(String.valueOf(203.6665)).setScale(3, BigDecimal.ROUND_HALF_UP));

(3)、System.out.println(Math.round(203.6665 * 1000) / 1000.0d);

3、包装器类型

最糟糕的是碰到值相等但对象不是同一个,或者为null的情况,前者比较结果都是错的,后者会报NullPointerException。

Integer a = new Integer(33);

Integer b= new Integer(33);

if(a==b){

System.out.println("a与b相等");

}else{

System.out.println("a与b不相等");

}

//a与b不相等

由于a,b指向的是不同的实例,最后比较结果是不相等,这和我们期望的比较结果往往是不同的,如果把赋值为null,程序便会报错。

所以我们需要优先使用基本数据类型,在一些特别场合可以使用包装器类型,如使用集合类时对元素的操作,使用泛型时设置类型参数等等,在这些场景中,基本数据类型不允许被使用,正是包装器类型上场的时候。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2016-07-22,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 java达人 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档