当前位置: 首页 > article >正文

【Java基础系列】BigDecimal入门

一.基本介绍

1.什么是 BigDecimal?

BigDecimal 是 Java 中的一个类,用于表示任意精度的十进制数。它属于 java.math 包,并提供了高精度的浮点数运算。与基本数据类型的浮点数(如 floatdouble)不同,BigDecimal 可以表示精确的小数,并且不会出现舍入误差。

2.BigDecimal 特点?

主要的特点包括:

  1. 任意精度: BigDecimal 可以处理非常大或非常小的数字,而不会失去精度。这对于需要精确计算货币、税收等金融领域的数据非常重要。

  2. 不受二进制浮点数表示误差的影响: 由于二进制浮点数表示法的限制,基本数据类型的浮点数可能会导致舍入误差。BigDecimal 使用基于十进制的表示,避免了这种误差。

  3. 支持精确的算术运算: BigDecimal 提供了一系列的算术运算方法,如加法、减法、乘法和除法,这些运算可以保持高精度。

  4. 不可变性: BigDecimal 对象是不可变的,一旦创建,就不能被修改。这有助于确保线程安全性。

  5. 丰富的方法: BigDecimal 提供了许多用于比较、取整、取余等操作的方法。

3.使用简介

以下是一个简单的示例,演示如何使用 BigDecimal 进行精确计算:

import java.math.BigDecimal;

public class BigDecimalExample {
    public static void main(String[] args) {
        BigDecimal num1 = new BigDecimal("10.5");
        BigDecimal num2 = new BigDecimal("2.3");

        // 加法
        BigDecimal sum = num1.add(num2);
        System.out.println("Sum: " + sum);

        // 减法
        BigDecimal difference = num1.subtract(num2);
        System.out.println("Difference: " + difference);

        // 乘法
        BigDecimal product = num1.multiply(num2);
        System.out.println("Product: " + product);

        // 除法,指定保留小数位数和舍入模式
        BigDecimal quotient = num1.divide(num2, 2, BigDecimal.ROUND_HALF_UP);
        System.out.println("Quotient: " + quotient);
    }
}

在这个示例中,BigDecimal 被用于执行精确的加法、减法、乘法和除法操作,并且可以通过指定保留小数位数和舍入模式来控制除法的结果。

二.使用简介

1.求和

求和

BigDecimal sum = Arrays.stream(bdArray).reduce(BigDecimal.ZERO, (p, q) -> p.add(q));
BigDecimal sum = list.stream().map(Person::getWeight)
                                .reduce(BigDecimal.ZERO, BigDecimal::add);

2.自定义求和

自定义求和

BigDecimal sum = map.values().stream().reduce(BigDecimal.ZERO, Utility::addWeight);
import java.math.BigDecimal;
public class Utility {
	public static BigDecimal addWeight(BigDecimal w1, BigDecimal w2) {
		return w1.add(w2);
	}
}

3.小数计算

小数

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
public class BigDecimalSumUsingList {
	public static void main(String[] args) {
		Person p1 = new Person("AAA", new BigDecimal("45.23"));
		Person p2 = new Person("BBB", new BigDecimal("55.43"));
		Person p3 = new Person("CCC", new BigDecimal("65.21"));
		Person p4 = new Person("DDD", new BigDecimal("35.73"));
		List<Person> list = Arrays.asList(p1, p2, p3, p4);
		BigDecimal sum = list.stream().map(Person::getWeight)
		                     .reduce(BigDecimal.ZERO, BigDecimal::add);
		System.out.println(sum);

		sum = list.stream().map(p -> p.getWeight())
                .reduce(BigDecimal.ZERO, (b1, b2) -> b1.add(b2));
		System.out.println(sum);

		sum = list.stream().map(Person::getWeight)
                .reduce(BigDecimal.ZERO, Utility::addWeight);
		System.out.println(sum);

	}
}

BigDecimal求和

BigDecimal sum = products.stream()
                .map(Product::getPrice)
                .reduce(BigDecimal.ZERO, BigDecimal::add);

先相乘再累加:

 final BigDecimal mgmtPrmAmt = value.stream()
                            .map(product -> product.getMgmtPrmAmt().multiply(new BigDecimal(product.getSalQty())))
                            .reduce(BigDecimal.ZERO, BigDecimal::add);

4.加减乘除

public BigDecimal add(BigDecimal value);  //加
public BigDecimal subtract(BigDecimal value);//减
public BigDecimal multiply(BigDecimal value);  //乘
public BigDecimal divide(BigDecimal value); //除

5.除法细节

RoundingMode类型:

  • ROUND_HALF_UP:根据保留数字后一位>=5 进行四舍五入
  • ROUND_UP:不管保留数字后面是大是小(0 除外)都会进 1
  • ROUND_DOWN:保留设置数字,后面所有直接去除
  • ROUND_HALF_DOWN:跟 ROUND_HALF_UP 差别仅在于 0.5 时会向下取整
  • ROUND_HALF_EVEN:取最近的偶数
  • ROUND_UNNECESSARY:不需要取整,如果存在小数位,就抛 ArithmeticException 异常
  • ROUND_CEILING:如果 BigDecimal 是正的,则做 ROUND_UP 操作;如果为负,则做 ROUND_DOWN 操作 (一句话:取附近较大的整数)
  • ROUND_FLOOR: 如果 BigDecimal 是正的,则做 ROUND_DOWN 操作;如果为负,则做 ROUND_UP 操作(一句话:取附近较小的整数)

BigDecimal 的 divide 方法是用于执行除法运算的,其语法如下:

#语法
public BigDecimal divide(BigDecimal divisor, int scale, RoundingMode roundingMode)

 #举例
 BigDecimal result = a.divide(b, 2, RoundingMode.HALF_UP);

其中,参数说明如下:

  • divisor:被除数,即要将当前 BigDecimal 对象除以的数。
  • scale:表示除法运算的结果要保留的小数位数。
  • roundingMode:表示舍入模式,用于在执行除法运算时确定如何舍入结果。

该方法返回一个 BigDecimal 对象,表示除法运算的结果。

import java.math.BigDecimal;
/**
 * @author : qinyingjie
 * @version : 2.2.0
 * @date : 2022/10/5 12:27
 */
class Scratch {
    public static void main(String[] args) {
        //Java中BigDecimal取整方法
        BigDecimal bd = new BigDecimal("12.1");
        long l1 = bd.setScale(0, BigDecimal.ROUND_UP).longValue(); // 向上取整
        long l2 = bd.setScale(0, BigDecimal.ROUND_DOWN).longValue(); // 向下取整
        System.out.println(l1);
        System.out.println(l2);
    }
}

要将 a 除以 b,并将结果保留 2 位小数,可以使用如下代码:

BigDecimal a = new BigDecimal("10");
BigDecimal b = new BigDecimal("3");
BigDecimal result = a.divide(b, 2, RoundingMode.HALF_UP);
System.out.println(result);

在上述代码中,RoundingMode.HALF_UP 表示使用“四舍五入”方式将结果舍入到 2 位小数。

需要注意的是,如果除数为 0,则会抛出 ArithmeticException 异常。另外,如果计算结果超出了 BigDecimal 能表示的范围,则会抛出 ArithmeticException 异常。因此,在使用 BigDecimal 进行除法运算时,需要对这些异常进行适当的处理。

6.BigDecimal 与 0 比较

BigDecimal 如何判断是否大于 0、小于 0 和等于 0

if (number.compareTo(BigDecimal.ZERO) == 0) {
    System.out.println("BigDecimal对象等于0");
} else {
    System.out.println("BigDecimal对象不等于0");
}

7.保留 4 位小数

取最大值并保留 4 位小数,使用的方法是一个数除以 1 等于它本身

max.setTotalSalQtyStoreRate(new BigDecimal(result.stream().mapToDouble(item -> Objects.nonNull(item.getTotalSalQtyStoreRate()) ? item.getTotalSalQtyStoreRate().doubleValue() : 0).max().getAsDouble())
                .divide(new BigDecimal(1), 4, BigDecimal.ROUND_DOWN));

8.注意点

注意点:

  1. 小数先转为 String,不然会出现精度错误
  2. 比较用 compareTo,并且比较 0,用 BigDecimal.ZERO
  3. 除法时要确定保留小数的位数,不然有可能出现除不尽的情况
  4. 如果传入的字符串是一个非法的数值(null、字母、空),NumberFormatException 异常,
  5. 非空校验

BigDecimal divide(BigDecimal divisor, int scale, int roundingMode)

roundingMode 为四舍五入的规则模型,用常量 int 来表示


http://www.kler.cn/news/155974.html

相关文章:

  • GB/T 37380-2019抗污易洁涂膜玻璃检测
  • Paxos 算法
  • 算法通关村第十六关-白银挑战滑动窗口经典题目
  • 第十七章 其他-rpc、rabbitmq(如何对消息做持久化、如何控制消息被消费的顺序)、celery(应用场景、运行机制、如何实现定时任务)
  • postgres在docker中使用
  • LeetCode刷题---反转链表
  • SCAU:链表创建与插入结点(填空)
  • word表格图片批处理参考程序
  • Linux-usb触摸板去除鼠标箭头
  • Ubuntu20.24 安装ecCodes,包括 tar.gz 和 python(笔记)
  • [网络安全]dos命令
  • Sakila数据库和World数据库
  • Vue+ElementUI+C#前后端分离:监控长耗时任务的实践
  • [足式机器人]Part4 南科大高等机器人控制课 Ch00 课程简介
  • C语言,求取数组的序亏:已知一个整数数组,求出个数组中每个元素在整个 数组的排序。
  • 鸿蒙(HarmonyOS)应用开发——构建页面(题目答案)
  • 93. 复原 IP 地址
  • 华为手环配置技巧
  • Java 中 IO 流分为几种?
  • 【算法思考记录】力扣1423. 可获得的最大点数[Python3, 滑动窗口]
  • golang 实现单向链表(lru)、双向链表、双向循环链表
  • Error:cannot launch node of type [map_server/map_server]
  • A++ 敏捷开发-1 如何改善
  • 常微分方程组的数值解法(C++)
  • WPS开发文档
  • Android:BackStackRecord
  • KALI LINUX安全审核
  • 实时设计#N3期训练营DONE,ComfyUI中文社区@上海
  • 再谈项目管理中的效率问题
  • “此应用专为旧版android打造,因此可能无法运行”,问题解决方案