概述
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 省略了模式,其实就是默认了模式,默认为 UNNECESSARY UNNECESSARY 用于断言,所以如果结果需要舍入的话,,则会抛出异常 |
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的名字起的不太规范,容易让人迷惑,使用时要注意。
最后
以上就是玩命海燕为你收集整理的[十七]基础类型BigDecimal简介的全部内容,希望文章能够帮你解决[十七]基础类型BigDecimal简介所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复