BigDecimal应用——计算费用场景中用到Integer,Double,BigDecimal三种类型出现的意外情况 结合BigDecimal源码分析

引出
在一个计算费用的场景中,用到了Integer,Double,BigDecimal三种类型,在转换为bigdecimal的时候遇到的问题,结合源码进行了分析。
- 1.在new bigdecimal的时候,最好传入的是字符串;
- 2.double类型在计算费用的场景中尽量不要用,会有意想不到的结果;
- 3.有时候用一下BigDecimal.valueOf方法是个不错的选择;
背景描述
最近在做一个物流相关的项目,其中有一个计算运费的模块,接收前端传的参数如下如所示

业务逻辑
然后需要根据这两个值,重量和体积计算运费,计算的业务逻辑如下所示
重量计算方法:
取重量和体积两者间较大的数值,体积计算方法:长(cm)×*宽(cm)*×高(cm)/轻抛系数
普快:
同城互寄:12000
城内寄件:12000
跨省寄件:12000
经济区互寄(京津翼、江浙沪皖、川渝):6000
经济区互寄(黑吉辽):9000
计费重量小数点规则:
不满1kg,按1kg计费;
10KG以下:以0.1kg为计重单位,四舍五入保留 1 位小数;
10-100KG:续重以0.5kg为计重单位,不足0.5kg按0.5kg算,四舍五入保留 1 位小数;
100KG及以上:四舍五入取整;
举例:
8.4kg按照8.4kg收费
8.5kg按照8.5kg收费
8.8kg按照8.8kg收费
18.1kg按照18.5kg收费
18.5kg按照18.5kg收费
18.7kg按照19kg收费
108.4kg按照108kg收费
108.5kg按照109kg收费
108.6kg按照109kg收费
总运费小数点规则:按四舍五入计算,精确到小数点后一位
我的方法及问题
由于double类型计算金钱相关的在Java中尽量不用,因此我把他们都转成bigdecimal进行计算,我写的代码如下

public static BigDecimal get(BigDecimal weight){if (weight.compareTo(new BigDecimal(1))<=0){weight = new BigDecimal(1); // 不满1kg,按照1kg计算return weight;}if (weight.compareTo(new BigDecimal(10))<=0){ // 10kg 以下DecimalFormat df = new DecimalFormat("#.0");String formattedNumber = df.format(weight);return new BigDecimal(formattedNumber);}// 四舍五入的计费规则DecimalFormat df = new DecimalFormat("#"); // 100kg 以上df.setRoundingMode(RoundingMode.HALF_UP);if (weight.compareTo(new BigDecimal(100))>0){return new BigDecimal(df.format(weight));}// 以0.5位计重单位BigDecimal remainder = weight.remainder(BigDecimal.ONE); // 小数部分BigDecimal integerPart = weight.divide(BigDecimal.ONE, BigDecimal.ROUND_DOWN); // 整数部分if (remainder.compareTo(new BigDecimal(0.5))>0){weight = weight.add(new BigDecimal(1)); // 18.7变成19df = new DecimalFormat("#.0");String formattedNumber = df.format(weight);return new BigDecimal(formattedNumber);}return new BigDecimal("1").add(integerPart);}
测试遇到的问题
测试的时候,发现输出的结果有些能对的上,有些就显得很奇怪,一开始百思不得其解,后来突然想到这个是不是浮点数的原因,再看我传的参数

我传的参数其实是double类型

idea其实也给了提示,我也忽略了这一条提醒

问题的对比分析
如果传的是一个double类型,比如18.8,则会出现下面的情况

如果用的是valueOf的方法,则不会出现上述的问题

源码分析
遇到上述问题后,好奇的Arya猫病又犯了,于是去翻了一下源码,发现了问题的所在,且听说来分析分析
1.valueOf方法
valueOf实际调用了什么方法

2.new BigDecimal(double d)方法
传入double类型的构造方法如下,调了double的这个方法:doubleToLongBits

这个方法干了啥事,把double类型用long类型的位表示

3.问题的本质

总结
1.在new bigdecimal的时候,最好传入的是字符串;
2.double类型在计算费用的场景中尽量不要用,会有意想不到的结果;
3.有时候用一下BigDecimal.valueOf方法是个不错的选择;
相关文章:
BigDecimal应用——计算费用场景中用到Integer,Double,BigDecimal三种类型出现的意外情况 结合BigDecimal源码分析
引出 在一个计算费用的场景中,用到了Integer,Double,BigDecimal三种类型,在转换为bigdecimal的时候遇到的问题,结合源码进行了分析。 1.在new bigdecimal的时候,最好传入的是字符串;2.double类…...
数据抓取可以应用到哪些行业
随着互联网的发展,数据已经成为人们生活中不可或缺的一部分。数据抓取作为获取数据的重要手段之一,也被广泛应用于各个行业。本文将探讨数据抓取在各个行业中的应用。 首先,让我们来了解一下数据抓取的基本概念。数据抓取是指通过一定的技术…...
目标检测YOLO实战应用案例100讲-面向小目标检测的多尺度特征融合(续)
目录 3.3 实验结果及分析 3.3.1 实验设置 3.3.2 消融实验 3.3.3 在PASCAL VOC2007上的结果...
如何选择适合的美颜SDK?
美摄美颜SDK是一款专门为企业提供美颜技术支持的SDK,可以帮助企业开发出具有高品质美颜效果的移动应用。本文将介绍美摄美颜SDK的技术特点和面向企业提供的技术支持。 一、技术特点 美摄美颜SDK采用了先进的图像处理技术和人工智能算法,能够快速准确地…...
Spring-底层架构核心概念
Spring底层核心组件 BeanDefinition BeanDefinition表示Bean定义,有很多属性用来描述Bean的特点: class,表示Bean类型 scope,表示Bean作用域,单例或原型等 lazyInit:表示Bean是否是懒加载 initMethod…...
RabbitMQ初入门
1、RabbitMQ是什么 RabbitMQ是“实现了高级消息队列协议(AMQP)的开源消息代理软件(亦称面向消息的中间件)。RabbitMQ服务器是用Erlang语言编写的,而集群和故障转移是构建在开放电信平台框架上的。所有主要的编程语言均…...
电脑定时关机
电脑定时关机 1.右键 管理 2. 3. 4. 5. shutdown.exe/s /f /t 06.点击完成就好了 7.这里面可以 看到定时任务和启动 右键有运行 结束 禁用...
【算法】滑动窗口题单——4.不定长滑动窗口(求子数组个数)
文章目录 前言2799. 统计完全子数组的数目解法1——枚举右端点,移动左端点解法2——枚举左端点,扩展右端点 713. 乘积小于 K 的子数组1358. 包含所有三种字符的子字符串数目2302. 统计得分小于 K 的子数组数目2537. 统计好子数组的数目2762. 不间断子数组…...
CMake aux_source_directory 学习
如下,prj是空文件夹; add.h; #include <iostream>using namespace std;int add1(int a, int b); num.h; int num1100; int num2301; add.cpp; #include "add.h"int add1(int i, int j) {return i j; } main.cpp&#x…...
Mybatis中延迟加载~
延迟加载: 等一会加载,在多表关联查询操作的时候可以使用到的一种方案,如果是单表操作就完全没有延迟加载的概念。 多表查询例如,查询用户和部门信息,如果我们仅仅只是需要用户的信息,而不需要用户对应的…...
【C语言】memmove()函数(拷贝重叠内存块函数详解)
🦄个人主页:修修修也 🎏所属专栏:C语言 ⚙️操作环境:Visual Studio 2022 目录 一.memmove()函数简介 1.函数功能 2.函数参数 1>.void * destination 2>.onst void * source 3>.size_t num 3.函数返回值 4.函数头文件 二.memmove()函数…...
04-流媒体-ffmpeg.c源码分析
ffmpeg.c是一个使用ffmpeg库的参考代码,实现了视频格式转换的功能,类似于我们常用的格式工产,源代码的的目录是: ffmpeg-4.2.2/fftools/ffmpeg.c 和前面的ffplay一样,我们分析其源代码,主要只是为了让读者了解ffmpeg.c此文件的大概流程,并且熟悉常用的ffmpeg库的API。 下…...
迭代器 Iterator
迭代器是一种设计模式,它用于遍历集合或容器中的元素,能够访问集合的元素而无需关心集合的内部结构: 特点: 封装集合访问:迭代器封装了对集合元素的访问,通过迭代器访问集合中的元素,而无需了…...
掌握CSS Flexbox,打造完美响应式布局,适配各种设备!
🎬 江城开朗的豌豆:个人主页 🔥 个人专栏 :《 VUE 》 《 javaScript 》 📝 个人网站 :《 江城开朗的豌豆🫛 》 ⛺️ 生活的理想,就是为了理想的生活 ! 目录 ⭐ 专栏简介 📘 文章引言 基…...
FlutterUnit 周边 | 收录排序算法可视化
theme: cyanosis 1. FlutterUnit 更新:排序算法可视化 排序算法可视化是用视图层表现出算法执行过程中排序的过程,感谢 编程的平行世界 在 《十几种排序算法的可视化效果,快来看看!👀》》 一文中提供的算法支持。我进行…...
代码随想录Day30 贪心05 LeetCode T435无重叠区间 T763划分字母区间 T56 合并区间
LeetCode T435 无重叠区间 题目链接:435. 无重叠区间 - 力扣(LeetCode) 题目思路: 这题思路和昨天的打气球类似,我们需要按照左区间或者右区间进行排序,然后哦判断第i个区间的左端点和第i-1个区间的右端点的大小关系,,如果大于等于,那么就无需操作,一旦…...
发展高质量存储力,中国高科技力量聚浪成潮
中国信息通信研究院指出,在全球数字化转型与产业变革的浪潮下,算力正在成为改变全球竞争格局的关键力量。而根据最新的《算力基础设施高质量发展行动计划》,算力是集信息计算力、数据存储力和网络运载力于一体的新型生产力。当前,…...
修改svc的LoadBalancer的IP引发的惨案
文章目录 背景修改externalIPs的操作api-server报错日志挽救教训 背景 k8s集群没有接外部负载均衡,部署istio的时候ingressgateway一直pending。 于是手动修改了这个lb svc的externalIP,于是k8s就崩了,如何崩的,且听我还道来。 …...
2520. 统计能整除数字的位数
2520. 统计能整除数字的位数 class Solution {public int countDigits(int num) {int res 0;int o num;while (num > 0) {if (o % (num % 10) 0) {res 1;}num num / 10;}return res;} }...
BeanUtils.copyProperties的用法
常见场景 我们如果有两个具有很多相同属性名的JavaBean对象a和b,想把a中的属性赋值到b,例如 接口中将接收到的前端请求参数XxxReqVo,我们想把这个入参转化为XxxQuery对象作为数据库的查询条件对象 传统做法是手动set,即 XxxQuery xxxQuer…...
C++实现分布式网络通信框架RPC(3)--rpc调用端
目录 一、前言 二、UserServiceRpc_Stub 三、 CallMethod方法的重写 头文件 实现 四、rpc调用端的调用 实现 五、 google::protobuf::RpcController *controller 头文件 实现 六、总结 一、前言 在前边的文章中,我们已经大致实现了rpc服务端的各项功能代…...
阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...
Qt Http Server模块功能及架构
Qt Http Server 是 Qt 6.0 中引入的一个新模块,它提供了一个轻量级的 HTTP 服务器实现,主要用于构建基于 HTTP 的应用程序和服务。 功能介绍: 主要功能 HTTP服务器功能: 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...
[10-3]软件I2C读写MPU6050 江协科技学习笔记(16个知识点)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16...
学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1
每日一言 生活的美好,总是藏在那些你咬牙坚持的日子里。 硬件:OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写,"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...
鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/
使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题:docker pull 失败 网络不同,需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...
Java + Spring Boot + Mybatis 实现批量插入
在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法:使用 MyBatis 的 <foreach> 标签和批处理模式(ExecutorType.BATCH)。 方法一:使用 XML 的 <foreach> 标签ÿ…...
基于SpringBoot在线拍卖系统的设计和实现
摘 要 随着社会的发展,社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 在线拍卖系统,主要的模块包括管理员;首页、个人中心、用户管理、商品类型管理、拍卖商品管理、历史竞拍管理、竞拍订单…...
力扣热题100 k个一组反转链表题解
题目: 代码: func reverseKGroup(head *ListNode, k int) *ListNode {cur : headfor i : 0; i < k; i {if cur nil {return head}cur cur.Next}newHead : reverse(head, cur)head.Next reverseKGroup(cur, k)return newHead }func reverse(start, end *ListNode) *ListN…...
