Java BigDecimal总结

2023-11-09

Java BigDecimal总结

概述

BigDecimal类在Java的java.math包中,可以处理超过16位有效位数的精确运算,而双精度浮点类型double只能处理16位有效数。

float 和 double的问题

float a = 1.0F;
float b = 0.9F;
System.out.println(a - b); //0.100000024

问题分析:

执行结果是0.100000024而不是0.1,这是因为计算机的资源是有限的,所以没办法用二进制精确到表示0.1,只能用近似值来表示,也就是在有限的精度下,最大化接近0.1的二进制数,这样也就出现了精度缺少的问题。

创建BigDecimal对象

可以使用new BigDecimal() BigDecimal.value()的这2种方式创建BigDecimal对象。

BigDecimal a = new BigDecimal(0.1);
BigDecimal b = BigDecimal.valueOf(0.1);
System.out.println(a); //0.1000000000000000055511151231257827021181583404541015625
System.out.println(b); //0.1

问题分析:

使用new BigDecimal() 仍然会出现精度问题,而使用BigDecimal.valueOf()则不会出现精度问题。

BigDecimal.valueOf()源码分析

public static BigDecimal valueOf(double val) {
    return new BigDecimal(Double.toString(val));
}

valueOf()方法的内部是先调用toString()方法,将浮点类型转为字符串,然后再使用构造方法创建对象。因此在使用构造方法创建对象时,应优先传递字符串类型。

将参数改为字符串后没有了精度问题:

BigDecimal c = new BigDecimal("0.1");
System.out.println(c); //0.1

equals() 和 compareTo()

比较2个BigDecimal对象,可以使用equals()compareTo()

BigDecimal a = new BigDecimal("0.01");
BigDecimal b = new BigDecimal("0.010");
System.out.println(a.equals(b)); //false
System.out.println(a.compareTo(b)); //0

问题分析:

equals()方法不仅比较2个对象的值是否相等,还比较精度是否相同。

compareTo()方法仅比较值的大小,返回值为:

  • -1:小于
  • 0:等于
  • 1:大于

因此,如果只比较2个对象的值的大小,则使用compareTo();如果严格限制精度的比较,则使用equals()

BigDecimal设置精度和舍入模式

在使用BigDecimal进行运算时,一定要设置精度和舍入模式,否则会出现以下问题:

BigDecimal a = new BigDecimal("1");
BigDecimal b = new BigDecimal("3");
System.out.println(a.divide(b));

报异常:

Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
	at java.base/java.math.BigDecimal.divide(BigDecimal.java:1722)

问题分析:

这是因为在做除法运算时,遇到一个无限小数0.3333…,不是一个精确到数字,因此抛出ArithmeticException异常。

舍入模式介绍

入模式定义在RoundingMode枚举类中,共有8种:

  • RoundingMode.UP:舍入远离零的舍入模式。在丢弃非零部分之前始终增加数字(始终对非零舍弃部分前面的数字加1)。注意,此舍入模式始终不会减少计算值的大小。
  • RoundingMode.DOWN:接近零的舍入模式。在丢弃某部分之前始终不增加数字(从不对舍弃部分前面的数字加1,即截短)。注意,此舍入模式始终不会增加计算值的大小。
  • RoundingMode.CEILING:接近正无穷大的舍入模式。如果 BigDecimal 为正,则舍入行为与 ROUNDUP 相同;如果为负,则舍入行为与 ROUNDDOWN 相同。注意,此舍入模式始终不会减少计算值。
  • RoundingMode.FLOOR:接近负无穷大的舍入模式。如果 BigDecimal 为正,则舍入行为与 ROUNDDOWN 相同;如果为负,则舍入行为与 ROUNDUP 相同。注意,此舍入模式始终不会增加计算值。
  • RoundingMode.HALF_UP:向“最接近的”数字舍入,如果与两个相邻数字的距离相等,则为向上舍入的舍入模式。如果舍弃部分 >= 0.5,则舍入行为与 ROUND_UP 相同;否则舍入行为与 ROUND_DOWN 相同。注意,这是我们在小学时学过的舍入模式(四舍五入)。
  • RoundingMode.HALF_DOWN:向“最接近的”数字舍入,如果与两个相邻数字的距离相等,则为上舍入的舍入模式。如果舍弃部分 > 0.5,则舍入行为与 ROUND_UP 相同;否则舍入行为与 ROUND_DOWN 相同(五舍六入)。
  • RoundingMode.HALF_EVEN:向“最接近的”数字舍入,如果与两个相邻数字的距离相等,则向相邻的偶数舍入。如果舍弃部分左边的数字为奇数,则舍入行为与 ROUNDHALFUP 相同;如果为偶数,则舍入行为与 ROUNDHALF_DOWN 相同。注意,在重复进行一系列计算时,此舍入模式可以将累加错误减到最小。此舍入模式也称为“银行家舍入法”,主要在美国使用。四舍六入,五分两种情况。如果前一位为奇数,则入位,否则舍去。以下例子为保留小数点1位,那么这种舍入方式下的结果。1.15 ==> 1.2 ,1.25 ==> 1.2
  • RoundingMode.UNNECESSARY:断言请求的操作具有精确的结果,因此不需要舍入。如果对获得精确结果的操作指定此舍入模式,则抛出ArithmeticException。

常用的四舍五入也就是RoundingMode.HALF_UP

加入精度和舍入模式后除法运算就正常了。

BigDecimal a = new BigDecimal("1");
BigDecimal b = new BigDecimal("3");
System.out.println(a.divide(b, 2, RoundingMode.HALF_UP)); //0.33

BigDecimal转字符串

BigDecimal对象转字符串有3种方法:

  • toPlainString():不适用科学计数法,通常使用最多。
  • toString():使用科学计数法。
  • toEngineeringString():使用工程计数法。

在这里插入图片描述

BigDecimal a = BigDecimal.valueOf(100000000000000000000.11);
System.out.println(a.toPlainString()); //100000000000000000000
System.out.println(a.toString()); //1.0E+20
System.out.println(a.toEngineeringString()); //100E+18

DecimalFormat 格式化

占位符 说明
0 数字占位符,位数不够时补0
# 数字占位符,位数不够时省略
. 小数点占位符
DecimalFormat format1 = new DecimalFormat("##.##");
System.out.println(format1.format(123.456)); //123.46
System.out.println(format1.format(3.4)); //3.4

DecimalFormat format2 = new DecimalFormat("00.00");
System.out.println(format2.format(123.456)); //123.46
System.out.println(format2.format(3.4)); //03.40

总结

  1. 如果使用new BigDecimal()方式创建对象,一定要传入字符串;否则使用BigDecimal.valueOf()方式创建对象。
  2. BigDecimal对象比较值大小时推荐使用compareTo()方法。
  3. 使用BigDecimal运算时一定要设置精度和舍入模式。
  4. BigDecimal转字符串推荐使用toPlainString()方法。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java BigDecimal总结 的相关文章

随机推荐

  • helm下

    讲师 李振良 官方网站 http www ctnrs com 第三章 Helm应用包管理器 下 说明 强烈建议学习课堂视频 更多细节都在里面 本文档为内部学员资料 请不要随意转发 3 6 Chart模板 Helm最核心的就是模板 即模板化的
  • xci转nsp工具_再谈xci、nsz、nsp

    每次群里有人问到进相册的homebrew为什么装不了补丁 或者说刚拉进去的文件为什么读取不到 老白之前推荐的aw 适用大气层 后期有改版aw适用TX tinleaf 适用于TX aw和tinleaf可以直接安装xci nsp nsz 安装n
  • 【爬虫】selenium+webdrive抓取淘宝商品评价

    爬虫 selenium webdrive抓取淘宝商品评价 爬虫小白入门 声明 本人只是处于突如其来的兴趣学习一点点 水平实在不高 但在这个过程中也或多或少地解决了一些问题 所以对同为小白的朋友们或许有用 但还请大神们不要笑我 动手前必备的知
  • DispatcherServlet工作原理简介说明

    转自 DispatcherServlet工作原理简介说明 下文笔者将讲述DispatcherServlet的工作流程 如下所示 当DispatcherServlet接到请求时 他先回查找适当的处理程序来处理请求 DispatcherServ
  • C语言中signal函数简介及使用

    signal h是C标准函数库中的信号处理部分 定义了程序执行时如何处理不同的信号 信号用作进程间通信 报告异常行为 如除零 用户的一些按键组合 如同时按下Ctrl与C键 产生信号SIGINT C 中的对应头文件是csignal C语言标准
  • Jenkins Android项目编译配置(完整版)

    Jenkins编译项目配置 环境要求 Jenkins准备 安装 启动 初始化 全局配置 全局工具 Global Tool Configuration 凭据 项目示例 General 源码管理 构建触发器 构建环境 构建 构建后操作 需要的插
  • C++ 函数覆盖

    C 函数覆盖 在派生类和基类中都定义了相同的函数 如果使用派生类的对象调用这个函数 派生类的函数就会被执行 这在 C 中称为函数覆盖 派生类中的函数覆盖基类中的函数 示例 1 C 函数覆盖 include
  • cblas_sgemm和cublasSgemm参数详解

    机器学习最核心的底层运算肯定是矩阵乘法无疑了 为了让矩阵乘法执行更快 大家也是绞尽脑汁 从算法层面 stranssen算法将矩阵乘法复杂度由 O n 3 O n 3 O n3 降
  • SSH方式连接Git及报错处理:RPC failed; result=22, HTTP code = 502

    Git作为常用的分布式版本控制系统 当前十分流行 我们已经介绍过有关Git进行版本控制的内容 但在实际使用Git过程中还是会遇到各种问题 今天就针对一个Git报错进行处理 通过HTTPS的git地址 clone到本地 初始一个项目包 add
  • Android Studio开发环境

    Android Studio 开发环境 React Native创建项目需要 java 开发环境 gt jdk 只需配置环境变量 gradle 只需配置环境变量 Android Studio 安装Android Studio Android
  • 固态硬盘启动计算机时间,装了固态硬盘开机还是慢,其实是忽略了这些...

    原标题 装了固态硬盘开机还是慢 其实是忽略了这些 你的电脑开机速度打败了全国百分之多少的用户 每天是否需要等上一段时间电脑才会开机 如果是这样 有人会说你该换个固态硬盘了 温馨提醒哦 这几个问题不解决 换了也没用 一 自检太慢 可以在BIO
  • 聊聊Java中的异常及处理

    前言 在编程中异常报错是不可避免的 特别是在学习某个语言初期 看到异常报错就抓耳挠腮 常常开玩笑说编程1分钟 改bug1小时 今天就让我们来看看什么是异常和怎么合理的处理异常吧 异常与error介绍 下面还是先让我们来看一下基本概念吧 异常
  • * \r \r\n \t的区别,是什么意思

    n 软回车 在Windows 中表示换行且回到下一行的最开始位置 相当于Mac OS 里的 r 的效果 在Linux unix 中只表示换行 但不会回到下一行的开始位置 r 软空格 在Linux unix 中表示返回到当行的最开始位置 在M
  • 【保姆式教程】用PowerDesigner导出数据库表结构为Word/Excel表格

    使用PowerDesigner将表结构导出到word表格 一 PowerDesigner的下载安装 已安装的跳过 PowerDesigner下载地址 后面只要next gt gt next gt gt finish 将track目录中的文件
  • 信奥赛和少儿编程的区别

    信奥赛和少儿编程的区别 现在的家长在培养孩子的学习的时候 可以说是非常的用心 他们会给孩子选择一些能够提升孩子能力的课程 就拿现在很多的家长想要孩子去学习少儿编程的课程来说 他们对于少儿编程和信息学奥赛的区别并不是很清楚 今天我们就一起来了
  • 类加载机制

    类的加载的机制 主要从两个方面回答 我们自己写的java文件到最终的运行 它必须经过编译和类加载这两个阶段 编译的过程就是把 java文件编程成class文件 类加载过程 就是把 class文件加载到JVM内存中 装载完成后会得到一个cla
  • 在浏览器上调试公众号网页的操作流程

    痛点说明 在实际开发过程中 公众号或者小程序开发都涉及到授权登录 我们最初原始的做法都是写好代码后 发布在测试环境中 然后再进行调试 有一个头痛的点在于如果你要验证你的想法 改动js的话 那么必须重新打包编译 打包和发布都是非常耗时的 引出
  • matlab大作业含代码_目标检测

    点击上方 AI算法修炼营 选择加星标或 置顶 标题以下 全是干货 来自 知乎 作者丨初识CV 来源丨https zhuanlan zhihu com p 102817180 仅作学术交流 如有侵权 请联系删文 一 数据增强 数据增强是增加深
  • Blender 2.8安装插件及如何找到打开插件

    安装插件 编辑 设置 插件 搜索 下载 安装 找到插件 安装的插件可在其下拉列表中看到所在位置 实在找不到 直接搜索
  • Java BigDecimal总结

    文章目录 Java BigDecimal总结 概述 float 和 double的问题 创建BigDecimal对象 BigDecimal valueOf 源码分析 equals 和 compareTo BigDecimal设置精度和舍入模