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

Double使用注意事项

目录

  • 数据精度问题
  • BigDecimal的正确使用
    • 构造陷阱
    • 数值比较
    • 除法
    • 舍入控制 `RoundingMode`

数据精度问题

Java开发中,Double类作为包装类用于处理双精度浮点数。浮点数double无法精确表示某些十进制小数(如0.1),导致运算结果出现误差

double a = 0.1;
double b = 0.2;
System.out.println(a + b); // 输出 0.30000000000000004,而非0.3

需要精确计算的场景需要使用:BigDecimal,并通过字符串构造避免初始精度丢失。

BigDecimal d1 = new BigDecimal("0.1");
BigDecimal d2 = new BigDecimal("0.2");
System.out.println(d1.add(d2)); // 0.3

Double 比较推荐使用 Double.compare(a, b)

double a = 0.1;
double b = 0.1;
System.out.println(a == b); // trueDouble aD = 0.1;
Double bD = 0.1;
System.out.println(aD == bD); // false
System.out.println(Double.compare(aD, bD) == 0); // true

BigDecimal的正确使用

对于需要精确计算的场景,使用BigDecimal

构造陷阱

避免用double构造BigDecimal,否则传入的是不精确的二进制值。

double v = 0.946; 
System.out.println(v); // 输出正确,0.946
// 直接转 BigDecimal,实际内部值是不精确的二进制值,导致截取3位小数结果错误
double vv = new BigDecimal(v).setScale(3, RoundingMode.DOWN).doubleValue();
System.out.println(vv); // 输出错误值 0.945

正确做法:BigDecimal(字符串构造)

double vvv = new BigDecimal(String.valueOf(v)).setScale(3, RoundingMode.DOWN).doubleValue();
System.out.println(vvv); // 输出正确,0.946

数值比较

BigDecimal a = new BigDecimal("1.0");
BigDecimal b = new BigDecimal("1");
System.out.println(a.compareTo(b) == 0); // true,数值相等

除法

必须指定舍入模式和精度,处理无限小数

BigDecimal a = new BigDecimal("10");
BigDecimal b = new BigDecimal("3");
// 指定保留4位小数,四舍五入
BigDecimal result = a.divide(b, 4, RoundingMode.HALF_UP); // 3.3333

不处理无限小数会抛出异常 ArithmeticException

BigDecimal a = new BigDecimal("10");
BigDecimal b = new BigDecimal("3");
a.divide(b); // 抛出 ArithmeticException

舍入控制 RoundingMode

RoundingMode.UP 远离零方向舍入 2.53, -2.5-3
RoundingMode.DOWN 向零方向舍入 2.52, -2.5-2
RoundingMode.CEILING 向正无穷方向舍入 2.53, -2.5-2
RoundingMode.FLOOR 向负无穷方向舍入 2.52, -2.5-3
RoundingMode.HALF_UP 四舍五入(常用) 2.53, 2.42
RoundingMode.HALF_DOWN 五舍六入 2.52, 2.63

示例

// 测试数值
BigDecimal number = new BigDecimal("2.55");
String label = "正数 2.55";
int newScale = 1;System.out.println("--- 测试数值: " + label + " ---");// UP:远离零方向舍入
System.out.println("UP          : " + number.setScale(newScale, RoundingMode.UP));// DOWN:向零方向舍入
System.out.println("DOWN        : " + number.setScale(newScale, RoundingMode.DOWN));// CEILING:向正无穷方向舍入
System.out.println("CEILING     : " + number.setScale(newScale, RoundingMode.CEILING));// FLOOR:向负无穷方向舍入
System.out.println("FLOOR       : " + number.setScale(newScale, RoundingMode.FLOOR));// HALF_UP:四舍五入
System.out.println("HALF_UP     : " + number.setScale(newScale, RoundingMode.HALF_UP));// HALF_DOWN:五舍六入
System.out.println("HALF_DOWN   : " + number.setScale(newScale, RoundingMode.HALF_DOWN));

结果展示,

--- 测试数值: 正数 2.55 ---
UP          : 2.6
DOWN        : 2.5
CEILING     : 2.6
FLOOR       : 2.5
HALF_UP     : 2.6
HALF_DOWN   : 2.5

负数注意 UP 和 CEILING,DOWN 和 FLOOR 的区别。

  • UP 是远离零方向(对负数是“向下舍入”,绝对值更大)。
  • CEILING 向正无穷方向(即对负数是“向上舍入”,更接近零),类似于数学中向上取整。
--- 测试数值: 负数 2.55 ---
UP          : -2.6
DOWN        : -2.5
CEILING     : -2.5
FLOOR       : -2.6
HALF_UP     : -2.6
HALF_DOWN   : -2.5

相关文章:

  • 【编程实践】利用open3d对点云进行聚类并可视化
  • Kotlin IR编译器插件开发指南
  • 互联网大厂Java求职面试:短视频平台大规模实时互动系统架构设计
  • Eigen 库实现最小二乘算法(Least Squares)
  • Unity基础学习(九)Resources资源同步与异步加载
  • 如何在 Linux 系统中永久禁用交换分区 ?
  • 实验绘图参考-0525版(自用)
  • PostgreSQL 与 MongoDB:为您的数据项目选择合适的数据库
  • 记录第一次正式收到SCI期刊论文的审稿
  • Ubantu22.04离线安装、卸载mysql8.0.39并设置开机自启
  • 深入理解 Linux 的 set、env 和 printenv 命令
  • 使用粘滞键修改windows密码
  • 医学写作供应商管理全流程优化
  • 前端课设Web2
  • 微服务——网关
  • 第九章 云平台开发
  • 测试工程师如何通俗理解和入门RAG:从“查资料”到“写答案”的智能升级
  • 如何使用Webpack实现异步加载?
  • OC语言学习——Foundation框架回顾及考核补缺
  • Three.js 海量模型加载性能优化指南
  • 腾宁网络做网站/stp营销战略
  • 惠州自适应网站建设/国内前10电商代运营公司
  • 网站改版具体建议/百度账号登录入口
  • 免费建设网站平台/在线网站seo优化
  • 福州网站建设哪家好/国内最大的搜索引擎
  • 万州电商网站建设/媒体发稿费用