Java中数值的加减乘除结果都是对的么?

简介: Java编程中,如果计算1.0-0.42得到的结果却不是0.58,其结果可和我们预期的是不一样的。本文将探讨这种特殊情况,并给出商业计算场景下如果用BigDecimal类型来化解这些问题。

    计算机程序内部都是二进制表示的,日常的编程实战中,除了处理字符串外,大部分情况下,都在处理数值的计算,如计算多个值的和或平均值。在Java语言体系中,关于数值的类型有int,float,double,long等。

    对于有小数的数值,开发人员首先想到的是可以用float或者double表示。比如求1.0和0.42两个值的差,那么心算可得0.58,但是如果用Java来实际计算一下,那么其结果可能和我们预期的是不一样的。

   下面结合特殊场景,来给出Java常见的数值加减乘除运算示例,看看结果都是对的么?具体的示例代码如下:

packagecom.jyd;
//Java 数值计算精度问题探讨示例publicclassNumDemo {
publicstaticvoidmain(String[] args) {
inta=10;
intc0=a/3 ;
System.out.println(c0);//3,只保留整数//float和double大部分情况精确的,但有时会计算错误// 在商业计算上(如金融、银行,财务),不建议使用。floatb=0.1f;
floatc2=b/3.0f;//0.033333335System.out.println(c2);
floatb2=20019999;
System.out.println(b2); //2.002E7doubled=45.9D;
doublec3=d/3.0D ;
System.out.println(c3);//15.299999999999999 (not 15.3)doublee=2001299.32D;
doublee2=0.11D;
System.out.println(e+e2); //2001299.4300000002System.out.println(1.0-0.42);//0.5800000000000001System.out.println(4.015*100);//401.49999999999994System.out.println(0.01+0.05);//0.060000000000000005    }
}

     上述示例代码中,int类型的数值10,/ 除以3,实际返回的是int类型,即3,只保留整数部分。这个计算结果只要我们知道,一般都可以理解。Java中的浮点类型(如float和double)采用 IEEE 754 标准。float类型的值0.1除以3.0时,返回的还是float类型的值,按照数学角度来说,应该返回0.3333...(循环),但是Java程序返回0.033333335。float类型长度为32位,其中1 位表示数字的符号,用 8 位表示指数,用 23 位表示小数部分。感觉这个长度有的长,但是实际使用起来精度还是不够。即使是64位的double也是如此。

    示例中,20019999这个float类型的值,输出后却是2.002E7,即20020000,真是奇乎怪哉!,如果这个是银行账户的金额,1个账户多1元,那么几亿个户头则多出了几个亿的金额,足见这个计算精度的问题是在特殊场景下,是一个不可接受的方案。 其他的示例涉及到加法、减法、乘法,也同样会出现计算错误的问题。
     按照官网的说法,float和double一般用于工程计算,而不能应用商业计算,如银行,财务等。那么商业计算上,该如何解决此问题呢?此时需要用到一个特殊的类型,为BigDecimal。此类型是一个精确的类型,下面给出示例:

packagecom.jyd;
importjava.math.BigDecimal;
importjava.math.MathContext;
//Java 数值计算精度问题探讨示例publicclassBigNumDemo {
publicstaticvoidmain(String[] args) {
BigDecimalb=newBigDecimal("0.1");
BigDecimalb1=newBigDecimal("3.0");
BigDecimalc2=b.divide(b1,10,BigDecimal.ROUND_DOWN) ;//0.0333333333System.out.println(c2);
BigDecimalb2=newBigDecimal(""+20019999);
System.out.println(b2); //20019999BigDecimald=newBigDecimal("45.9");
BigDecimald2=newBigDecimal("3.0");
BigDecimalc3=d.divide(d2,10,BigDecimal.ROUND_CEILING) ;
System.out.println(c3);//15.3000000000BigDecimale=newBigDecimal("2001299.32");
BigDecimale2=newBigDecimal("0.11");
System.out.println(e.add(e2)); //2001299.43BigDecimale3=newBigDecimal("1.0");
BigDecimale4=newBigDecimal("0.42");
System.out.println(e3.subtract(e4));//0.58BigDecimale5=newBigDecimal("4.015");
BigDecimale6=newBigDecimal("100");
System.out.println(e5.multiply(e6, MathContext.UNLIMITED));//401.500BigDecimale7=newBigDecimal("0.01");
BigDecimale8=newBigDecimal("0.05");
System.out.println(e7.add(e8));//0.06BigDecimale9=newBigDecimal("999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999");
System.out.println(e9.add(e3));//1000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000.0    }
}

      BigDecimal有多种构造函数,常用的有2种。建议使用String构造方式,不建议使用double构造方式,可能会出现精度丢失问题。通过上述示例可以看出,商业计算应该使用 BigDecimal类型来完成,虽然在加减乘除这块使用起来有点不够简便,但是仍然比较容易理解。且操作字符串,也更容易操作。在乘除计算中,强制需要制定额外的参数,比如明确小数个数,四舍五入的模式等。

    最后,Java编程的细节还有很多,比如不同精度的数值的赋值和转换问题,float和double为什么会导致数据精度的丢失等,可以参考官网文档或其他资料。这里不再赘述。

相关文章
|
7月前
|
Java
2048. 下一个更大的数值平衡数 --力扣 --JAVA
如果整数  x 满足:对于每个数位 d ,这个数位 恰好 在 x 中出现 d 次。那么整数 x 就是一个 数值平衡数 。 给你一个整数 n ,请你返回 严格大于 n 的 最小数值平衡数 。 0 <= n <= 106
146 3
|
Java
Java不用加减乘除做加法(图文详解)
1.题目描述 2.题解 分析 具体实现
68 0
|
6月前
|
Java
在Java中,你可以创建一个简单的四则运算程序来执行小学级别的加减乘除操作
【6月更文挑战第19天】Java程序实现简单四则运算,接收用户输入的两个数字和运算符,根据运算符调用相应函数进行计算。包含加、减、乘、除功能,其中除法操作检查了除数是否为零,避免运行时错误。
62 5
|
7月前
|
数据可视化 小程序 Java
【Java】——实现可视化加减乘除计算器
【Java】——实现可视化加减乘除计算器
【Java】——实现可视化加减乘除计算器
|
人工智能 Java BI
【Java基础】位运算实现加减乘除
&:按位与,对应位都为 1 时结果为 1,否则为 0。 |:按位或,对应位有一个为 1 时结果为 1,否则为 0。 ^:按位异或,对应位不同时结果为 1,否则为 0。 ~:按位取反,将每一位取反。 <<:左移,将所有位向左移动指定的位数,右边补零。
103 0
|
Java
浅谈Java中的NAN与INFINITY:数值迷失与无限可能
浅谈Java中的NAN与INFINITY:数值迷失与无限可能
540 0
|
7月前
|
Java Go C++
Rust每日一练(Leetday0024) 爬楼梯、简化路径、编辑距离
Rust每日一练(Leetday0024) 爬楼梯、简化路径、编辑距离
81 0
Rust每日一练(Leetday0024) 爬楼梯、简化路径、编辑距离
|
7月前
|
存储 Java 索引
Java数值类型提升机制
Java数值类型提升机制
77 0
|
存储 Java
Java中-BigDecimal类型如何进行加减乘除运算?
Java中-BigDecimal类型如何进行加减乘除运算
222 0
java202303java学习笔记第四十二天DQL-数值函数2
java202303java学习笔记第四十二天DQL-数值函数2
70 0