专栏首页noteless[十七]基础类型BigDecimal简介

[十七]基础类型BigDecimal简介

BigDecimal是不可变的、任意精度的、有符号的、十进制数.

组成部分

BigDecimal 由任意精度的整数非标度值 和 32 位的整数标度 (scale) 组成

BigDecimal 表示的数值是  : unscaledValue × 10的-scale 次幂

私有成员intVal就是非标度值

scale就是标度

标度

BigDecimal由非标度值 和 32 位的整数标度 (scale) 组成

BigDecimal表示的数为: unscaledValue × 10的-scale 次幂

显然

如果scale为零或正数,最终的结果中,小数点后面的位数就等于scale标度

比如: scale为1 10的-1次方,  0.1 小数点后有1位

如果 scale 是负数,那最终的结果将会是乘以 10的|scale| 次方

比如:  scale为-3 最终的值就是非标度值乘以 1000  (    10的(- -3)次方   )

精度

非标度值的数字个数

构造方法

几个关键概念  非标度值 标度 运算规则

构造方法就是围绕这几个点展开的

BigDecimal(BigInteger val)

将 BigInteger 转换为 BigDecimal

BigDecimal(BigInteger unscaledVal,int scale)

将 BigInteger 非标度值和 int 标度转换为 BigDecimal

BigDecimal(BigInteger unscaledVal,                    int scale,                    MathContext mc)

将 BigInteger 非标度值和 int 标度转换为 BigDecimal (根据上下文设置进行舍入)

BigDecimal(BigInteger val,MathContext mc)

将 BigInteger 转换为 BigDecimal(根据上下文设置进行舍入)

BigDecimal(char[] in, int offset, int len, MathContext mc)

将 BigDecimal 的字符数组表示形式转换为 BigDecimal允许指定子数组根据上下文设置进行舍入

BigDecimal(char[] in, int offset, int len)

上一个方法的简化默认形式

BigDecimal(char[] in)

简化形式

BigDecimal(char[] in, MathContext mc)

简化形式

BigDecimal(String val)

调用的BigDecimal(char[] in, int offset, int len)

BigDecimal(String val, MathContext mc)

调用的是BigDecimal(char[] in, int offset, int len, MathContext mc)

BigDecimal(int val)

int 转换为 BigDecimal

BigDecimal(int val, MathContext mc)

int 转换为 BigDecimal根据上下文设置进行舍入

BigDecimal(long val)

long 转换为 BigDecimal

BigDecimal(long val, MathContext mc)

long 转换为 BigDecimal根据上下文设置进行舍入

BigDecimal(double val)

double 转换为 BigDecimal

BigDecimal(double val, MathContext mc)

double 转换为 BigDecimal根据上下文设置进行舍入

构造方法注意事项

BigDecimal(double val)

BigDecimal(double val, MathContext mc)

这两个构造方法具有一定的不确定性

如下图所示,这是因为在二进制中无法准确地表示0.1 如同十进制无法准确表示 1/3 一样

当 double 必须用作 BigDecimal 的源时

请注意,此构造方法public BigDecimal(double val)提供了一个准确转换;

不等同于下面的操作:

先使用 Double.toString(double) 方法,

然后使用 BigDecimal(String) 构造方法

要获取该结果,请使用 static valueOf(double) 方法

String构造方法的格式

Sign(可选) Significand Exponent opt(可选)

Sign 符号: + -   Significand 有效数字至少要有整数或者小数的一位数字: IntegerPart .FractionPart  整数和小数 . FractionPart   小数 IntegerPart      整数   IntegerPart: Digits   FractionPart: Digits   Exponent:  指数部分 ExponentIndicator SignedInteger   ExponentIndicator: 指数符号 e E   SignedInteger: 有符号数 Sign(可选的) Digits   Digits: Digit Digits Digit   Digit: Character.isDigit(char) 对其返回 true 的任何字符,如 0、1、2……

-1.23E-12这是一个完整的格式含有符号  / 含有整数部分 / 含有小数部分 /含有指数部分/指数部分含有符号

除非有必要

否则在你需要 将 float 或 double 转换为 BigDecimal时

首选BigDecimal(String val)

构造方法与 Float.toString(float) 和 Double.toString(double) 返回的值兼容

它不会遇到 BigDecimal(double) 构造方法的不可预知问题

常量

内部定义了几个public final static int的常量,用于标注舍入模式

与RoundingMode中是一一对应的,这几个不要再使用了

请使用RoundingMode中的枚举值

ROUND_UP ROUND_DOWN   ROUND_CEILING ROUND_FLOOR   ROUND_HALF_UP ROUND_HALF_DOWN ROUND_HALF_EVEN   ROUND_UNNECESSARY

另外还有三个常用对象

public static final BigDecimal ZERO

public static final BigDecimal ONE

public static final BigDecimal TEN

常用方法

属性获取

int signum()

返回此 BigDecimal 的正负号函数负、零或正时,返回 -1、0 或 1

int scale()

返回此 BigDecimal 的标度

int precision()

返回此 BigDecimal 的精度。(精度是非标度值的数字个数。) 零值的精度是 1

BigInteger unscaledValue()

返回其值为此 BigDecimal 的非标度值 的 BigInteger

四则运算

除非结果准确,每种运算都有一个表示结果的首选标度

这些标度是返回准确算术结果的方法使用的标度

add(BigDecimal augend)

计算 this + augend 标度为: max(this.scale(), augend.scale())

add(BigDecimal augend, MathContext mc)

计算 this + augend 根据上下文设置进行舍入

subtract(BigDecimal subtrahend)

计算 this - subtrahend 标度为 : max(this.scale(), subtrahend.scale())

subtract(BigDecimal subtrahend, MathContext mc)

计算 this - subtrahend 根据上下文设置进行舍入

multiply(BigDecimal multiplicand)

计算 this × multiplicand 标度为 : (this.scale() + multiplicand.scale())

multiply(BigDecimal multiplicand, MathContext mc)

计算 this × multiplicand) 根据上下文设置进行舍入

divide(BigDecimal divisor, int scale, int roundingMode)

计算 this / divisor 指定标度 如果需要舍入则会使用指定的模式进行舍入   应该使用 divide(BigDecimal, int, RoundingMode) 进行替代

divide(BigDecimal divisor,           int scale,           RoundingMode roundingMode)

作为上面divide方法的替代 目前仍旧映射到原来的遗留方法上 将RoundingMode转换为了int 相对于上一个方法,应该优先使用这个方法

divide(BigDecimal divisor, int roundingMode)

简化转换形式

divide(BigDecimal divisor, RoundingMode roundingMode)

简化转换形式

divide(BigDecimal divisor)

计算 this / divisor首选标度为 (this.scale() - divisor.scale());如果无法表示准确的商值(因为它有无穷的十进制扩展)则抛出 ArithmeticException

divide(BigDecimal divisor, MathContext mc)

计算 this / divisor根据上下文设置进行舍入

divideToIntegralValue(BigDecimal divisor)

返回 BigDecimal值为向下舍入所得商值 (this / divisor) 的整数部分首选标度为 (this.scale() - divisor.scale())

divideToIntegralValue(BigDecimal divisor, MathContext mc)

返回 BigDecimal其值为 (this / divisor) 的整数部分准确商值的整数部分与舍入模式无关所以舍入模式不影响此方法返回的值首选标度是 (this.scale() - divisor.scale())如果准确商值的整数部分需要的位数多于 mc.precision则抛出 ArithmeticException

divideToIntegralValue 需要注意因为是取整数部分,所以舍入模式是不影响的

针对于参数MathContext 有影响的是精度

BigDecimal[] divideAndRemainder(BigDecimal divisor)

计算商和余数返回由两个元素组成的 BigDecimal 数组该数组包含 divideToIntegralValue 的结果后跟对两个操作数计算所得到的 remainder

BigDecimal[] divideAndRemainder(BigDecimal divisor, MathContext mc)

计算商和余数 返回由两个元素组成的 BigDecimal 数组 该数组包含 divideToIntegralValue 的结果 后跟 根据上下文设置对两个操作数进行舍入计算所得到的 remainder

remainder(BigDecimal divisor)

remainder(BigDecimal divisor, MathContext mc)

注意

如果同时需要整数商和余数

则divideAndRemainder比分别使用 divideToIntegralValue 和 remainder 方法更快速,因为相除仅需执行一次

remainder则是依赖于divideAndRemainder ,然后返回的第二个元素

数学方法

BigDecimal pow(int n) 求n次幂 准确计算该幂,使其具有无限精度 参数 n 必须在 0 到 999999999(包括)之间 ZERO.pow(0) 返回 ONE -如果 n 超出范围 抛出异常ArithmeticException

pow(int, MathContext)求n次幂使用的是 ANSI 标准 X3.274-1996 中定义的核心算法(根据上下文设置进行舍入)

BigDecimal abs()求绝对值其标度为 this.scale()

BigDecimal abs(MathContext mc)求绝对值根据上下文设置进行舍入

最大值max最小值min借助于compareTo

int compareTo(BigDecimal val)值相等但具有不同标度的两个 BigDecimal 对象(如,2.0 和 2.00)被认为是相等的 注意:与equals中的相等含义不同小于、等于或大于 val 时,返回 -1、0 或 1

equals

判断是否相等 与 compareTo 不同 仅当两个 BigDecimal 对象的值和标度都相等时,此方法才认为它们相等 (因此通过此方法进行比较时,2.0 不等于 2.00)

一定要注意到compareTo方法与equals方法 对于相等的定义是不一致的

valueOf

public static BigDecimal valueOf(long val)将 long 值转换为具有零标度的 BigDecimal这个方法优先于以long为参数的构造方法如下图所示,这个valueOf方法会进行缓存

public static BigDecimal valueOf(long unscaledVal, int scale)将 long 非标度值和 int 标度转换为 BigDecimal看得出来这个valueOf版本也是会借助于缓存的所以优先于构造方法

valueOf(double val)使用 Double.toString(double) 方法转换 double 为字符串并且 调用构造方法此方法并没有涉及到缓存回头看下上面说的String参数类型的构造方法String参数类型的构造方法---与 Float.toString(float) 和 Double.toString(double) 返回的值兼容这个valueOf借助的就是toString方法这个版本valueOf是float和double转换为BigDecimal的首选

setScale

setScale 系列并不是设置BigDecimal的scale  BigDecimal是不可变得

setScale 是一个转换器,将参数的BigDecimal转换为指定标度的值

值本身不会变化,变化的是形式

返回的是一个新的BigDecimal,不过这个新的BigDecimal并不一定是新创建的

可能是使用缓存,新是相对于调用者来说

方法列表:

public BigDecimal setScale(int newScale, int roundingMode)返回一个 BigDecimal其标度为指定值其非标度值通过此 BigDecimal 的非标度值乘以或除以十的适当次幂来确定,以维护其总值相对于此遗留方法,应优先使用新的 setScale(int, RoundingMode) 方法

public BigDecimal setScale(int newScale, RoundingMode roundingMode)setScale(int newScale, int roundingMode) 的替代形式使用RoundingMode枚举

BigDecimal setScale(int newScale)返回一个 BigDecimal其标度为指定值,其值在数值上等于此 BigDecimal 的值如果这不可能,则抛出 ArithmeticException省略了模式,其实就是默认了模式,默认为 UNNECESSARYUNNECESSARY 用于断言,所以如果结果需要舍入的话,,则会抛出异常

negate/plus/round

BigDecimal negate()取负数返回 BigDecimal,值为 (-this),标度为 this.scale()

BigDecimal negate(MathContext mc)根据指定上下文设置取负数返回其值为 (-this) 的 BigDecimal(根据上下文设置进行舍入)。

BigDecimal plus()返回本身  任何一个数前面加正号 都是它本身值为 (+this),标度为 this.scale()

BigDecimal plus(MathContext mc)返回其值为 (+this) 的 BigDecimal(根据上下文设置进行舍入)方法的效果与 round(MathContext) 方法的效果相同

BigDecimal round(MathContext mc)等同于BigDecimal plus(MathContext mc)

xxxValue

intValue()转换为 int丢弃此 BigDecimal 的小数部分如果生成的 "BigInteger" 太大而不适合用 int 表示,则仅返回 32 位低位字节此转换会丢失关于此 BigDecimal 值的总大小和精度的信息

longValue() 转换为 long 丢弃此 BigDecimal 的小数部分 如果生成的 "BigInteger" 太大 仅返回 64 位低位字节 此转换会丢失关于此 BigDecimal 值的总大小和精度的信息

floatValue()转换为 float如果BigDecimal 的值太大而不能表示为 float将其适当地转换为 Float.NEGATIVE_INFINITY 或 Float.POSITIVE_INFINITY此转换也可能丢失关于 BigDecimal 值精度的信息

doubleValue()转换为 double如果此 BigDecimal 的数量太大而不能表示为 double将其适当地转换为 Double.NEGATIVE_INFINITY 或 Double.POSITIVE_INFINITY转换也可能丢失关于 BigDecimal 值精度的信息

BigInteger toBigInteger()转换为 BigInteger丢弃此 BigDecimal 的小数部分此转换会丢失关于 BigDecimal 值的精度信息

XXXValueExact

byte byteValueExact()转换为 byte如果此 BigDecimal 具有非零小数部分,或者超出 byte 结果的可能范围则抛出 ArithmeticException

short shortValueExact()转换为 short如果此 BigDecimal 具有非零小数部分,或者超出 short 结果的可能范围则抛出 ArithmeticException

int intValueExact()转换为 int如果此 BigDecimal 具有非零小数部分,或者超出 int 结果的可能范围则抛出 ArithmeticException

long longValueExact()转换为 long如果此 BigDecimal 具有非零小数部分,或者超出 long 结果的可能范围则抛出 ArithmeticException

BigInteger toBigIntegerExact()转换为 BigInteger如果此 BigDecimal 具有非零小数部分,则抛出一个异常

exact版本的区别就在于是否能够准确转换,否则抛出异常

也就是他要么返回一个准确地值要么就抛出异常

hashCode

int hashCode()

返回此 BigDecimal 的哈希码数值上相等但标度不同的两个 BigDecimal 对象(如,2.0 和 2.00)通常没有 相同的哈希码

toString

toString() 返回字符串表示形式,如果需要指数,则使用科学记数法 toEngineeringString() 返回字符串表示形式,需要指数时,则使用工程计数法 toPlainString()  返回不带指数字段的此 BigDecimal 的字符串表示形式

toString的三个方法根本逻辑是一样的,都是转换为字符串只不过具体的形式不同

ulp

unit in the last place

两个数之间的距离,在数学中是无限的,比如1和2之间有无数个数

但是在计算机中是有限的,因为计算机需要用有限个字节来表示double或者float,计算机表示不了无限的数

因为没有无限内存

假设两个数之间有10个数,那么ulp 就是1/10 

1和2之间有一个数 距离为1

1.1和2.1之间有十个数  距离为0.1

这就是ulp

非零 BigDecimal 值的 ulp 是此值与下一个具有相同位数的较大 BigDecimal 值之间的正距离

零值的 ulp 在数值上等于1 和 this.scale()之间的距离

所以可以说所有的数的ulp为[1, this.scale()]

移动小数点

movePointLeft该值的小数点向左移动 n 位如果 n 为负数,则该调用等效于 movePointRight(-n)如果 n 为非负数,则调用仅将 n 添加到该标度返回的值和标度分别为:

movePointRight小数点向右移动 n 位如果 n 为负,则该调用等效于 movePointLeft(-n)如果 n 为非负数,则该调用仅从该标度减去 n返回的值和标度分别为:

BigDecimal scaleByPowerOfTen(int n)

返回其数值等于的BigDecimal该结果的标度为:

BigDecimal stripTrailingZeros()形式转换,数值是相等的转换为去掉所有尾部的0的形式的数值800.000去掉所有的0 就是8   准换后为8乘以10的平方

总结

BigDecimal虽然有诸多特性与特别,,但是本质仍旧是浮点数

所以自然提供了浮点数相关的一些操作

作为数值的基本运算方法都具备的

需要注意的是构造方法之间的区别

除非特别需要,否则不要直接使用double构造

尽可能的使用String的形式

对于valueOf方法也是具有缓存的

BigDecimal是不可变的

setScale的名字起的不太规范,容易让人迷惑,使用时要注意。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • HTTP协议简介详解 HTTP协议发展 原理 请求方法 响应状态码 请求头 请求首部 java模拟浏览器客户端服务端

    契约也即类似于合同,自然有甲方123...,乙方123...,哪些能做,哪些不能做;

    noteless
  • sleep、yield、join方法简介与用法 sleep与wait区别 多线程中篇(十四)

    Object中的wait、notify、notifyAll,可以用于线程间的通信,核心原理为借助于监视器的入口集与等待集逻辑

    noteless
  • 7.计算机网络的发展 计算机网络发展背景 原因 阿帕网与计算机网络 通信方式 电路 报文 分组 包 交换 卡恩 瑟夫 网络控制协议 NCP TCP ip诞生发展 tcp 协议族 应用编程接口

    https://baike.baidu.com/item/%E4%BA%92%E8%81%94%E7%BD%91%E5%8F%91%E5%B1%95%E5%8F...

    noteless
  • Java中的BigDecimal类你了解多少?

    可以看到在Java中进行浮点数运算的时候,会出现丢失精度的问题。那么我们如果在进行商品价格计算的时候,就会出现问题。很有可能造成我们手中有0.06元,却无法购买...

    用户1516716
  • 【答疑解惑】Java中的高精度数字

    前几天网友在群里有问BigDecimal能直接赋值吗?就像使用基本数据类型那样,答案是不能。 Java中的基本数据类型有的时候是不能满足实际编程需要的,特别是在...

    程序员互动联盟
  • Java开发中商业计算请务必使用BigDecimal来进行计算!

    今天群里一个初级开发者问为什么测试人员测出来他写的价格计算模块有计算偏差的问题,他检查了半天也没找出问题。这里小胖哥要提醒你,商业计算请务必使用`BigDeci...

    码农小胖哥
  • 为什么阿里巴巴禁止使用BigDecimal的equals方法做等值比较?

    BigDecimal,相信对于很多人来说都不陌生,很多人都知道他的用法,这是一种java.math包中提供的一种可以用来进行精确运算的类型。

    敖丙
  • Java-BigDecimal数据类型

    我们知道在Java中有float和double类型,它们的主要设计目标是为了科学计算和工程计算。然而,它们没有提供完全精确的结果【因为其有限的有效位数】,所以不...

    老九学堂-小师弟
  • BigDecimal和BigInteger

    我们知道计算机都是以二进制的形式存储数据的,而我们日常则是使用十进制,那么我们的 数字 存进计算机则需一个进制转换的过程,这过程就会损失精度的,就导致浮点数不能...

    晚上没宵夜
  • java中Integer运算保留2位小数

    1.整数型运算时,结果会自动去除小数点后面的部分,如果需要适当的保留几位小数,需要转为fload类型,分子或者分母或者都转

    IT云清

扫码关注云+社区

领取腾讯云代金券