数字的陷阱

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,程序便会报错。

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

原文发布于微信公众号 - java达人(drjava)

原文发表时间:2016-07-22

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏数据结构与算法

codevs 1213 解的个数

1213 解的个数 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题目描述 Description 已知整数x...

3384
来自专栏编程札记

java之hashtable和hashmap

1715
来自专栏Bingo的深度学习杂货店

Q119 Pascal's Triangle II

Given an index k, return the kth row of the Pascal's triangle. For example, give...

3658
来自专栏小樱的经验随笔

洛谷 P1598 垂直柱状图【字符串+模拟】

P1598 垂直柱状图 题目描述 写一个程序从输入文件中去读取四行大写字母(全都是大写的,每行不超过72个字符),然后用柱状图输出每个字符在输入文件中出现的次数...

3075
来自专栏SeanCheney的专栏

《Pandas Cookbook》第01章 Pandas基础

公司网址,http://www.dunderdata.com(dunder是蒸馏朗姆酒的残留液体,取这个名字是类比数据分析过程) GitHub地址:https...

1362
来自专栏Java帮帮-微信公众号-技术文章全总结

【编程题】Java编程题一(10道)

【编程题】Java编程题一(10道) 【程序1】 题目:古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,...

4278
来自专栏wannshan(javaer,RPC)

dubbo序列化过程源码分析

先看下dubbo在serialize层的类设计方案 序列化方案的入口,是接口Serialization的实现类。 /** * Serialization. ...

8099
来自专栏软件开发 -- 分享 互助 成长

C++ STL之排序算法

排序算法和查找算法差不多,也涉及到迭代器区间问题,关于该问题的注意事项就不在啰嗦了 一、全部排序sort、stable_sort sort是一种不稳定排序,使用...

1975
来自专栏wym

字符串--最长回文子串(暴力讲解+Manacher)

问题描述:给你一个字符串str,若子串s是回文串,则称s为str的回文子串,求s的最大长度

1842
来自专栏HansBug's Lab

2431: [HAOI2009]逆序对数列

2431: [HAOI2009]逆序对数列 Time Limit: 5 Sec  Memory Limit: 128 MB Submit: 954  Solv...

2846

扫码关注云+社区