Java中如何解决double和float精度不准的问题
JAVA 如何 解决 精度 float double 问题
2023-09-11 14:21:35 时间
我们知道浮点数是无法在计算机中准确表示的,例如0.1在计算机中只是表示成了一个近似值,因此,浮点数的运算结果具有不可预知性。
在进行数字运算时,如果有double或float类型的浮点数参与计算,偶尔会出现计算不准确的情况。如以下示例代码:
- package ex;
- public class BigDeciTest {
- public static void main(String[] args){
- System.out.println(0.05+0.01);
- System.out.println(1.0-0.42);
- System.out.println(4.015*100);
- System.out.println(123.3/100);
- }
- }
- 0.060000000000000005
- 0.5800000000000001
- 401.49999999999994
- 1.2329999999999999
在大多数情况下,使用double和float计算的结果是准确的,但是在一些精度要求很高的系统中,这种问题是非常严重的。
在《Effective Java》中提到一个原则,那就是float和double只能用来作科学计算或者是工程计算,但在商业计算中我们要用java.math.BigDecimal,通过使用BigDecimal类我们可以解决上述问题,实例代码如下:
- package ex;
- import java.math.*;
- public class BigDecimalDemo {
- public static void main(String[] args){
- System.out.println(ArithUtil.add(0.01, 0.05));
- System.out.println(ArithUtil.sub(1.0, 0.42));
- System.out.println(ArithUtil.mul(4.015, 100));
- System.out.println(ArithUtil.div(123.3, 100));
- }
- }
- class ArithUtil{
- private static final int DEF_DIV_SCALE=10;
- private ArithUtil(){}
- //精确的加法算法
- public static double add(double d1,double d2){
- BigDecimal b1=new BigDecimal(Double.toString(d1));
- BigDecimal b2=new BigDecimal(Double.toString(d2));
- return b1.add(b2).doubleValue();
- }
- //精确的减法算法
- public static double sub(double d1,double d2){
- BigDecimal b1=new BigDecimal(Double.toString(d1));
- BigDecimal b2=new BigDecimal(Double.toString(d2));
- return b1.subtract(b2).doubleValue();
- }
- //精确的乘法算法
- public static double mul(double d1,double d2){
- BigDecimal b1=new BigDecimal(Double.toString(d1));
- BigDecimal b2=new BigDecimal(Double.toString(d2));
- return b1.multiply(b2).doubleValue();
- }
- //相对精确的除法运算,当发生除不尽的情况时,精确到小数点以后10位
- public static double div(double d1,double d2){
- return div(d1,d2,DEF_DIV_SCALE);
- }
- //相对精确的除法运算,当发生除不尽的情况时,精确到小数点以后指定精度(scale),再往后的数字四舍五入
- public static double div(double d1,double d2,int scale){
- if(scale<0){
- throw new IllegalArgumentException("The scale must be a positive integer or zero");
- }
- BigDecimal b1=new BigDecimal(Double.toString(d1));
- BigDecimal b2=new BigDecimal(Double.toString(d2));
- return b1.divide(b2,scale,BigDecimal.ROUND_HALF_UP).doubleValue();
- }
- }
运行结果如下:
- 0.06
- 0.58
- 401.5
- 1.233
说明:
虽然BigDecimal类的构造方法很多,但是我们只使用了带String类型的构造函数。
1、BigDecimal(double val):构造函数的结果有一定的不可预知性,比如 new BigDecimal(0.1)可能认为就是0.1,但是实际上可能等于0.10000000006642423,这是因为0.1无法准确地表示double
2、BigDecimal(String val):构造函数是完全可以预知的。 new BigDecimal("0.1")创建的BigDecimal,正好等于预期的0.1
相关文章
- java集合(3)- Java中的equals和hashCode方法详解
- java语音转文字
- Java中有哪些无锁技术来解决并发问题?如何使用?
- Java 中有哪些无锁技术来解决并发问题?如何使用?
- Java泛型
- java实现给图片添加水印(文字水印或图片水印)
- 【Java】Eclipse如何创建java项目并运行
- 【Harmony OS】【JAVA UI】鸿蒙应用如何集成OKHttp网络三方库
- maven项目的java和resources等文件夹不在Java Resources的文件夹里,并且缺少Deployment...
- Tomcat 奔溃:java.lang.OutOfMemoryError: Java heap space
- SpringCloud OpenFeign使用和配置,Java OpenFeign 使用教程
- Java中如何使用Redis做缓存
- java高并发,如何解决,什么方式解决
- IDEA如何清晰地查看Java类的继承结构及该类的所有方法?
- 浅析AES加密工作模式 EBC/CBC 模式了解及具体如何进行补位、AES加密报错java.security.InvalidAlgorithmParameterException: ECB mode cannot use IV处理
- 浅析Java如何使用@ControllerAdvice、@ExceptionHandler进行全局统一异常处理、如何使用@responseBodyAdvice进行全局统一返回值处理
- Java的Maven基础知识笔记:Maven是什么、maven目录、pom.xml唯一ID、maven解决依赖管理、maven中央仓库与镜像、构建流程(声明周期、阶段、目标)、使用插件、模块管理、mvnw指定版本、如何发布自己的开源库
- Java中的lambda表达式如何理解——精简
- 【HarmonyOS】【JAVA UI】HarmonyOS如何集成Gson
- 实操代码研究各种Java技术-java.toutiao.im
- Java数据结构与算法 day04 递归
- ehcache memcache redis -- java中的三大缓存
- java中如何忽略字符串中的转义字符--转载
- 【Java养成】:编程基础详解,从语法开始一点点详解!
- Java-购物车实践与应用