BigDecimal创建应使用String参数构造方法或value of方法,否则会有精度丢失

本文主要是介绍BigDecimal创建应使用String参数构造方法或value of方法,否则会有精度丢失,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、BigDecimal.valueOf(double val):

这个方法是专门为浮点数设计的,它试图为给定的 double 值提供一个精确的 BigDecimal 表示。
当你传递一个 double 值给 valueOf 方法时,它并不直接使用该 double 的二进制表示。相反,它首先检查这个 double 是否能精确地表示为长整数(即没有小数部分),如果是,则使用长整数来构建 BigDecimal。
如果 double 值包含小数部分,则 valueOf 方法会使用一个更精确的算法来将 double 转换为 BigDecimal,这通常涉及将 double 分解为它的各个部分(符号、指数、尾数等),并据此构造 BigDecimal。
因此,对于 BigDecimal.valueOf(0.01),它通常会给出精确的结果,因为该值可以相对容易地以精确的方式转换为 BigDecimal。

二、new BigDecimal(double val):

当你使用这种构造函数时,BigDecimal 直接使用传入的 double 值的二进制表示来构建 BigDecimal。
但是,由于许多 double 值(尤其是小数)在二进制中不能精确表示(就像十进制中的 1/3 不能精确表示为有限小数一样),因此这种转换可能会导致精度损失。
这就是为什么直接使用 new BigDecimal(0.01) 可能会得到一个有轻微精度损失的结果的原因。
总之,为了避免在将浮点数转换为 BigDecimal 时出现精度问题,最好使用 BigDecimal.valueOf(double val) 方法,而不是直接使用 new BigDecimal(double val) 构造函数。

三、new BigDecimal(“0.01”):

这个构造函数直接接受一个字符串参数。
字符串 “0.01” 在内存中是以字符数组的形式存储的,每个字符都有一个明确的ASCII值。
BigDecimal 的这个构造函数会解析这个字符串,按照十进制数制规则来构建内部的数值表示。
因为字符串精确地表示了数字0.01,所以这种方式没有精度损失。

四、new BigDecimal(“0.01”)与BigDecimal.valueof(0.01)创建时底层有什么区别吗

在比较 new BigDecimal(“0.01”) 和 BigDecimal.valueOf(0.01) 创建 BigDecimal 对象时底层的区别时,实际上有一点需要澄清:BigDecimal.valueOf(0.01) 并不直接接受一个 double 类型的字面量作为参数,而是接受一个 double 类型的值作为参数,但这个值通常是通过字面量或其他方式(如计算)得到的。
不过,为了回答你的问题,我们可以从它们如何处理参数和内部实现的角度来讨论:
new BigDecimal(“0.01”):
这个构造函数直接接受一个字符串参数。
字符串 “0.01” 在内存中是以字符数组的形式存储的,每个字符都有一个明确的ASCII值。
BigDecimal 的这个构造函数会解析这个字符串,按照十进制数制规则来构建内部的数值表示。
因为字符串精确地表示了数字0.01,所以这种方式没有精度损失。

BigDecimal.valueOf(0.01):
这个静态方法接受一个 double 类型的参数(尽管这里你写的是一个 double 字面量0.01,但它在被传递给方法之前已经被转换成了 double 类型的值)。
这个 double 值在内存中是以IEEE 754浮点数格式存储的,可能不是0.01的精确表示。
但是,BigDecimal.valueOf 方法并没有直接使用这个 double 值的二进制表示来构建 BigDecimal。相反,它使用了一种更精确的方式来处理这个 double 值。
具体来说,valueOf 方法会检查这个 double 值是否可以精确地表示为一个长整数(即没有小数部分)。如果可以,它就直接使用长整数来构建 BigDecimal。如果不能,它会将 double 值分解为它的各个部分(符号、指数、尾数等),并据此精确地构建 BigDecimal。
因此,虽然你传递的是一个 double 值给 valueOf 方法,但该方法会尽量避免由于 double 不精确表示导致的精度损失。
总结来说,虽然 new BigDecimal(“0.01”) 和 BigDecimal.valueOf(0.01) 在表面上看起来都接受了一个表示0.01的参数,但它们在底层处理这个参数的方式是不同的。new BigDecimal(“0.01”) 直接解析字符串来构建 BigDecimal,而 BigDecimal.valueOf(0.01) 则使用了一种更精确的方式来处理 double 值,以避免精度损失。

五、BigDecimal.valueof(0.01)为啥没有精度问题,而new BigDecimal(0.01)有精度问题

BigDecimal是Java中用于解决浮点数运算精度问题的一个类,它提供了精确的数值运算能力。在处理涉及精度要求较高的场合,如金融计算时,BigDecimal的使用尤为重要。关于BigDecimal.valueOf(0.01)new BigDecimal(0.01)在精度问题上的差异,可以从以下几个方面进行分析:

  1. 计算机存储机制

    • 二进制表示:计算机内部使用二进制系统来表示和存储所有的数据,包括十进制的浮点数。由于二进制无法精确表示某些十进制小数,因此在转换过程中可能会产生精度损失[1]。
    • 浮点数表示:计算机中的浮点数由指数和尾数两部分组成,这种表示方法可能会导致一些浮点数运算产生误差[3]。
  2. 构造函数差异

    • BigDecimal.valueOf(double val):这个静态方法在底层实际上是将传入的double值先转换为字符串,然后再创建BigDecimal对象。这样做的好处是避免了直接使用double值可能带来的精度损失[4]。
    • new BigDecimal(double val):使用这个构造函数会直接根据传入的double值创建一个BigDecimal对象,但由于double值本身的精度问题,创建的BigDecimal对象可能会包含不精确的值[3]。
  3. 精度丢失风险

    • 直接使用double:当直接使用double类型的字面量作为参数时,可能会因为二进制表示的限制而引入精度误差。
    • 字符串转换:通过字符串创建BigDecimal可以避免这种精度丢失,因为字符串中的每个数字都是精确的。
  4. 推荐做法

    • 优先使用BigDecimal.valueOf():为了避免精度丢失,建议使用BigDecimal.valueOf()方法来创建BigDecimal对象[2][4]。
    • 使用字符串构造函数:或者使用new BigDecimal(String val)构造函数,将需要精确表示的浮点数先转换为字符串,再创建BigDecimal对象。
  5. 阿里巴巴Java开发手册建议

    • 避免使用基本数据类型:《阿里巴巴 Java 开发手册》中提到,浮点数之间的等值判断不应该使用基本数据类型的==来比较,因为这可能会因为精度问题导致错误的比较结果[1]。
    • 使用BigDecimal进行精确计算:手册中还提到,涉及到钱等需要精确计算结果的场景应该使用BigDecimal来进行运算。
  6. 实际案例

    • 金融计算:在金融领域,比如货币的加减乘除,精确到分的计算是必须的,这时候使用BigDecimal可以保证计算的准确性。
    • 科学计算:在科学计算中,对精度的要求也非常高,使用BigDecimal可以避免因为浮点数的精度问题导致的计算错误。
  7. 注意事项

    • 除法运算:在使用BigDecimal进行除法运算时,应该注意使用带有三个参数的divide方法,并选择合适的舍入模式,以避免无法除尽时出现的异常[1]。
    • 大小比较:使用compareTo方法进行大小比较,而不是使用==来判断两个BigDecimal对象是否相等。
  8. 其他方法

    • add、subtract、multiply、divide:这些方法分别用于执行加法、减法、乘法和除法运算,它们保证了运算的精确性[1]。
    • toString、doubleValue、floatValue、longValue、intValue:这些方法用于将BigDecimal对象转换为其他类型的对象,但需要注意的是转换后的对象可能无法保持原有的精度。

综上所述,BigDecimal.valueOf(0.01)没有精度问题是因为它通过将double值转换为字符串的方式来创建BigDecimal对象,从而避免了直接使用double值可能带来的精度损失。而new BigDecimal(0.01)有精度问题的原因在于它直接使用了可能存在精度误差的double值来创建BigDecimal对象。因此,在实际开发中,为了确保精度,应优先考虑使用BigDecimal.valueOf()方法或通过字符串构造函数来创建BigDecimal对象。

这篇关于BigDecimal创建应使用String参数构造方法或value of方法,否则会有精度丢失的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1036189

相关文章

中文分词jieba库的使用与实景应用(一)

知识星球:https://articles.zsxq.com/id_fxvgc803qmr2.html 目录 一.定义: 精确模式(默认模式): 全模式: 搜索引擎模式: paddle 模式(基于深度学习的分词模式): 二 自定义词典 三.文本解析   调整词出现的频率 四. 关键词提取 A. 基于TF-IDF算法的关键词提取 B. 基于TextRank算法的关键词提取

使用SecondaryNameNode恢复NameNode的数据

1)需求: NameNode进程挂了并且存储的数据也丢失了,如何恢复NameNode 此种方式恢复的数据可能存在小部分数据的丢失。 2)故障模拟 (1)kill -9 NameNode进程 [lytfly@hadoop102 current]$ kill -9 19886 (2)删除NameNode存储的数据(/opt/module/hadoop-3.1.4/data/tmp/dfs/na

Hadoop数据压缩使用介绍

一、压缩原则 (1)运算密集型的Job,少用压缩 (2)IO密集型的Job,多用压缩 二、压缩算法比较 三、压缩位置选择 四、压缩参数配置 1)为了支持多种压缩/解压缩算法,Hadoop引入了编码/解码器 2)要在Hadoop中启用压缩,可以配置如下参数

Makefile简明使用教程

文章目录 规则makefile文件的基本语法:加在命令前的特殊符号:.PHONY伪目标: Makefilev1 直观写法v2 加上中间过程v3 伪目标v4 变量 make 选项-f-n-C Make 是一种流行的构建工具,常用于将源代码转换成可执行文件或者其他形式的输出文件(如库文件、文档等)。Make 可以自动化地执行编译、链接等一系列操作。 规则 makefile文件

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传

Andrej Karpathy最新采访:认知核心模型10亿参数就够了,AI会打破教育不公的僵局

夕小瑶科技说 原创  作者 | 海野 AI圈子的红人,AI大神Andrej Karpathy,曾是OpenAI联合创始人之一,特斯拉AI总监。上一次的动态是官宣创办一家名为 Eureka Labs 的人工智能+教育公司 ,宣布将长期致力于AI原生教育。 近日,Andrej Karpathy接受了No Priors(投资博客)的采访,与硅谷知名投资人 Sara Guo 和 Elad G

C++11第三弹:lambda表达式 | 新的类功能 | 模板的可变参数

🌈个人主页: 南桥几晴秋 🌈C++专栏: 南桥谈C++ 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据库学习专栏: 南桥谈MySQL 🌈Qt学习专栏: 南桥谈Qt 🌈菜鸡代码练习: 练习随想记录 🌈git学习: 南桥谈Git 🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈�

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

如何在页面调用utility bar并传递参数至lwc组件

1.在app的utility item中添加lwc组件: 2.调用utility bar api的方式有两种: 方法一,通过lwc调用: import {LightningElement,api ,wire } from 'lwc';import { publish, MessageContext } from 'lightning/messageService';import Ca

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal