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简介的更多相关文章

  1. [十六]基础类型BigInteger简介

        BigInteger和BigDecimal都是Java针对大数提供的类 超出了java的表示范围   属性简介 借助于signum和mag 来实现数据的符号位和实际数据的保存 final in ...

  2. 玩转JavaScript OOP[0]——基础类型

    前言 long long ago,大家普遍地认为JavaScript就是做一些网页特效的.处理一些事件的.我身边有一些老顽固的.NET程序员仍然停留在这种认知上,他们觉得没有后端开发肯定是构建不了系统 ...

  3. FeWeb基础之JavaScript简介

    FeWeb基础之JavaScript简介 1.JavaScript的基本介绍 JavaScript是一种基于对象和事件驱动并具有安全性能的脚本语言,它是通过嵌入或调入在标准的HTML语言中实现的.Ja ...

  4. AspectJ基础学习之一简介(转载)

    AspectJ基础学习之一简介(转载) 一.为什么写这个系列的博客   Aspectj一个易用的.功能强大的aop编程语言.其官网地址是:http://www.eclipse.org/aspectj/ ...

  5. JAVA基础-基础类型

    学习JAVA的同学都知道,数据类型是基础中的基础,而JAVA本身是强类型语言,他对变量的类型有这魔一般的执著,所以学好JAVA的重心就是要学好数据类型.既然有强类型语言,就会有弱类型语言如PHP.Ja ...

  6. salesforce 零基础学习(五十八)通过sObject的field返回其对应的基础类型

    项目中有时候会要求通过sObject的Field的type类型返回其对应的基本类型,然后对其进行相关的处理,创建sObject的field可以选择的type类型是固定多的. 上述类型可以转换成几种基本 ...

  7. TypeScript 素描-基础类型

    博文读自 TypeScript 官方文档而来,不具有学习性,仅是本人学习时记录以供日后翻阅 ,有学习TypeScript的朋友还请去看更为详细的官方文档 TypeScript官网文档中的基础类型, T ...

  8. Typescript基础类型

    1.布尔值__boolean 2.数字__number----除了支持十进制和十六进制字面量,Typescript还支持ECMAScript 2015中引入的二进制和八进制字面量. 3.字符串__st ...

  9. 框架基础之Hibernate简介

    框架基础之Hibernate简介 1.什么是Hibernate? Hibernate是一个开发源代码的对象关系映射框架,它对JDBC进行非常轻量级的对象封装,使得程序员可以随心所欲地使用对象编程思维来 ...

随机推荐

  1. go 统计目录大小

    文件大小获取 // 这里获取的是 FileInfo 对象 fi, _ := os.Stat(filepath) FileInfo 定义如下: type FileInfo interface { Nam ...

  2. mybatis invalid comparison: java.sql.Timestamp and java.lang.String报错解决方法

    这个错的意思是:java.sql.Timestamp和java.lang.String无效的比较 错误的原因是:拿传入的时间类型参数与空字符串进行比较就会报这个异常 解决方法:只保留非null判断就可 ...

  3. web 11

    Obtaining the JSON: 1.首先,我们将把要检索的JSON的URL存储在变量中. 2.要创建请求,我们需要使用new关键字从XMLHttpRequest构造函数创建一个新的请求对象实例 ...

  4. Android手机ROM刷机简介

    这一段时间刷了一堆ROM,安卓系列.CM.Hero.OldMos.隔壁新出的Android2.0,反正都尝了一下鲜,手机的照相机也刷得再也启不来了(不知道什么原因,杯具).有话说:"久病成良 ...

  5. A_B_Good Bye 2018_cf

    A. New Year and the Christmas Ornament time limit per test 1 second memory limit per test 256 megaby ...

  6. VIM常用快捷键(转载)

    移动光标 h,j,k,l 上,下,左,右 ctrl-e 移动页面 ctrl-f 上翻一页 ctrl-b 下翻一页 ctrl-u 上翻半页 ctrl-d 下翻半页 w 跳到下一个字首,按标点或单词分割 ...

  7. 浅谈开发中python通过os模块存储数据

    #其实本人很烦发博客,但为了面试还是发一下好,证明一下自己的能力 前言 首先说一下适用环境,在开发中我们有一些经常用到的数据(数据量大)需要存储起来. 存sql嘛又不合适,要知道在开发中每条sql语句 ...

  8. python—文件处理

    一.文件处理流程 1.打开文件,得到文件句柄并赋值 2.通过句柄对文件进行操作 3.关闭文件 二.文件打开模式 1.r,只读,默认模式 2.w,只写 3.a,追加 4. r+.w+.x+.a+ ,可读 ...

  9. ubuntu connect to windows folder share

    在windows上给远程登录的用户设置一个账号密码.”右击计算机图标“——"管理”——“本地用户和组”——“用户”.然后右击选择“新用户”,输入账号密码,并勾选“密码永不过期”,这样,在远程 ...

  10. CoreProfiler升级到.NetStandard 2.0

    致所有感兴趣的朋友: CoreProfiler和相应的Sample项目cross-app-profiling-demo都已经升级到.NetStandrard 2.0和.NetCore 2.0. 有任何 ...