1 浮点数据
浮点数据有单精度浮点数据和双精度浮点数据,对应Java中的基础数据类型为:
float和double,数据描述如下表:
序号 | 数据类型 | 描述 | 有效位 |
---|---|---|---|
1 | float | 单精度 | 8位 |
2 | double | 双精度 | 17位 |
float和double的有效数据位数是全部数据的位数,而不是小数点后面的位数,因此会出现数据精度丢失的问题。解析如下图:
由图1.1可知,float的有效数字为8位,是所有数字组成的8位,即:
f l o a t 有效数字位数 = 小数点前面的数字位数 + 小数点后面的数字位数 float有效数字位数=小数点前面的数字位数+小数点后面的数字位数 float有效数字位数=小数点前面的数字位数+小数点后面的数字位数
而不是指小数点后面的有效数字位数,因此,当,需要使用保留小数点后3位或更多位数的需求时,小数点前面的数字位数达6位以上,小数点后最多保留两位,因此会出现数据精度丢失。
由图1.2可知,double的有效数字为17位,是所有数字组成的17位,即:
d
o
u
b
l
e
有效数字位数
=
小数点前面的数字位数
+
小数点后面的数字位数
double有效数字位数=小数点前面的数字位数+小数点后面的数字位数
double有效数字位数=小数点前面的数字位数+小数点后面的数字位数
同样,如果小数点前面数据过多,仍会导致数据精度降低。
1.1 有效位测试
package function;
import java.math.BigDecimal;
import java.util.logging.Logger;
import static common.constant.DigitalConstant.THREE;
/**
* 数据计算.
*
* @author xindaqi
* @date 2021-05-13 13:44
*/
public class DataProcessTest {
private static final Logger logger = Logger.getLogger("DataProcessTest");
public static void main(String[] args) {
double a = 10.123456789012345678;
logger.info("双精度数据:" + a);
float b = 1.12345678f;
logger.info("单精度数据:" + b);
}
}
1.2 结果与解析
运行结果:
五月 14, 2021 10:22:23 上午 function.DataProcessTest main
信息: 双精度数据:10.123456789012346
五月 14, 2021 10:22:23 上午 function.DataProcessTest main
信息: 单精度数据:1.1234568
由运行结果可知,
- float有效位:8位;
- double有效位:17位;
- float数据在第8位进行四舍五入;
- double数据在第17位四舍五入。
2 BigDecimal
为解决数据精度丢失问题,Java提供了BigDecimal保证数据精度,并在计算时可以定制小数点后面精确位数。
源码中的取舍案例如下图所示:
2.1 Usage
package function;
import java.math.BigDecimal;
import java.util.logging.Logger;
import static common.constant.DigitalConstant.THREE;
/**
* 数据计算.
*
* @author xindaqi
* @date 2021-05-13 13:44
*/
public class DataProcessTest {
private static final Logger logger = Logger.getLogger("DataProcessTest");
public static void main(String[] args) {
BigDecimal num1 = new BigDecimal("0.01");
BigDecimal num2 = new BigDecimal("0.003");
BigDecimal num3 = new BigDecimal("4.8929183");
logger.info("BigDecimal加法:" + num1.add(num2));
logger.info("BigDecimal减法:" + num1.subtract(num2));
logger.info("BigDecimal乘法:" + num2.multiply(num3));
logger.info("BigDecimal除法:" + num3.divide(num2, THREE, BigDecimal.ROUND_HALF_UP));
}
}
2.2 结果与解析
运行结果:
五月 14, 2021 10:22:23 上午 function.DataProcessTest main
信息: BigDecimal加法:0.013
五月 14, 2021 10:22:23 上午 function.DataProcessTest main
信息: BigDecimal减法:0.007
五月 14, 2021 10:22:23 上午 function.DataProcessTest main
信息: BigDecimal乘法:0.0146787549
五月 14, 2021 10:22:23 上午 function.DataProcessTest main
信息: BigDecimal除法:1630.973
由运行结果可知,
- BigDecimal进行加减乘计算时,默认保留了所有数据,小数点后有几位即保留几位
- BigDecimal进行除法计算时,需要指定小数点后保留的有效数据位数和数据取舍的规则
2.3 数据取舍规则
BigDecimal提供了8中数据取舍规则,详细结束如下表
序号 | 取舍规则 | 描述 |
---|---|---|
1 | ROUND_UP | 小数点后数字大于0即进位 |
2 | ROUND_DOWN | 小数点后数字全部舍弃,置为0 |
3 | ROUND_CEILING | 数字大于0,即进位,数字小于0则,小数点后数字全部舍弃,置为0 |
4 | ROUND_FLOOR | 数字小于0,即进位,数字大于0,小数点后数字全部舍弃,置为0 |
5 | ROUND_HALF_UP | 小数点后数字四舍五入,大于等于5进位 |
6 | ROUND_HALF_DOWN | 小数点后数字五舍六入,大于等于6进位 |
7 | ROUND_HALF_EVEN | 小数点后数字四舍六入五考虑,五前为偶舍弃,五前为奇进位 |
8 | ROUND_UNNECESSARY | 不需要舍入 |
按照取舍规则取数样例如下表所示,参考:java.math.RoundingMode。
序号 | 样例数字 | UP | DOWN | CEILING | FLOOR | HALF_UP | HALF_DOWN | HALF_EVEN |
---|---|---|---|---|---|---|---|---|
1 | 5.5 | 6 | 5 | 6 | 5 | 6 | 5 | 6 |
2 | 2.5 | 3 | 2 | 3 | 2 | 3 | 2 | 2 |
3 | 1.6 | 2 | 1 | 2 | 1 | 2 | 2 | 2 |
4 | 1.1 | 2 | 1 | 2 | 1 | 1 | 1 | 1 |
5 | 1.0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
6 | -1.0 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
7 | -1.1 | -2 | -1 | -1 | -2 | -1 | -1 | -1 |
8 | -1.6 | -2 | -1 | -1 | -2 | -2 | -2 | -2 |
9 | -2.5 | -3 | -2 | -2 | -3 | -3 | -2 | -2 |
10 | -5.5 | -6 | -5 | -5 | -6 | -6 | -5 | -6 |
【参考文献】
[1]https://www.cnblogs.com/maoxiuying/p/8522241.html
[2]https://blog.csdn.net/androidstar_cn/article/details/52916489
[3]https://blog.csdn.net/mqdxiaoxiao/article/details/88937674
[4]https://blog.csdn.net/ratter/article/details/84611558
[5]https://zhidao.baidu.com/question/1926154311505686867.html