zoukankan      html  css  js  c++  java
  • [十七]基础类型BigDecimal简介

     

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

    image_5bdbee29_1474
     

    组成部分

    BigDecimal 由任意精度的整数非标度值 和 32 位的整数标度 (scale) 组成
    BigDecimal 表示的数值是  :
    unscaledValue × 10的-scale 次幂
    私有成员intVal就是非标度值
    scale就是标度

    image_5bdbee29_6a7

     

    标度

    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) 上一个方法的简化默认形式
    image_5bdbee29_24ba
    BigDecimal(char[] in) 简化形式
    image_5bdbee29_7fe7
    BigDecimal(char[] in, MathContext mc) 简化形式
    image_5bdbee29_53df
    BigDecimal(String val)
    调用的BigDecimal(char[] in, int offset, int len)
    image_5bdbee29_566a
    BigDecimal(String val, MathContext mc) 调用的是BigDecimal(char[] in, int offset, int len, MathContext mc)
    image_5bdbee29_6a0
     
     
    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 一样
    image_5bdbee29_74ea
     
    当 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
    image_5bdbee29_79fb
     

    四则运算

    除非结果准确,每种运算都有一个表示结果的首选标度
    这些标度是返回准确算术结果的方法使用的标度
    image_5bdbee29_54ed
     
    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)
    image_5bdbee29_37d5
    作为上面divide方法的替代
    目前仍旧映射到原来的遗留方法上
    将RoundingMode转换为了int
    相对于上一个方法,应该优先使用这个方法
    divide(BigDecimal divisor, int roundingMode) 简化转换形式
    image_5bdbee29_45c4
    divide(BigDecimal divisor, RoundingMode roundingMode) 简化转换形式
    image_5bdbee29_768a
    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) image_5bdbee29_755
    remainder(BigDecimal divisor, MathContext mc) image_5bdbee29_810
     

    注意

    如果同时需要整数商和余数
    则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
    image_5bdbee29_573c
    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方法会进行缓存
    image_5bdbee29_758c
    public static BigDecimal valueOf(long unscaledVal, int scale)
    将 long 非标度值和 int 标度转换为 BigDecimal
    看得出来这个valueOf版本也是会借助于缓存的
    所以优先于构造方法
    image_5bdbee2a_3754
    valueOf(double val)
    使用 Double.toString(double) 方法转换 double 为字符串
    并且 调用构造方法

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

    setScale

    setScale 系列并不是设置BigDecimal的scale  BigDecimal是不可变得
    setScale 是一个转换器,将参数的BigDecimal转换为指定标度的值
    值本身不会变化,变化的是形式
    返回的是一个新的BigDecimal,不过这个新的BigDecimal并不一定是新创建的
    可能是使用缓存,新是相对于调用者来说
    image_5bdbee2a_355f
     
    方法列表:
    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枚举
    image_5bdbee2a_52d6
    BigDecimal setScale(int newScale)
    返回一个 BigDecimal
    其标度为指定值,其值在数值上等于此 BigDecimal 的值
    如果这不可能,则抛出 ArithmeticException

    省略了模式,其实就是默认了模式,默认为 UNNECESSARY
    UNNECESSARY 用于断言,所以如果结果需要舍入的话,,则会抛出异常
    image_5bdbee2a_63b5
     

    negate/plus/round

    BigDecimal negate()
    取负数
    返回 BigDecimal,值为 (-this),标度为 this.scale() 
    BigDecimal negate(MathContext mc)
    根据指定上下文设置取负数
    返回其值为 (-this) 的 BigDecimal(根据上下文设置进行舍入)。
    image_5bdbee2a_7058
    BigDecimal plus()
    返回本身  任何一个数前面加正号 都是它本身
    值为 (+this),标度为 this.scale()
    image_5bdbee2a_729b
    BigDecimal plus(MathContext mc)
    返回其值为 (+this) 的 BigDecimal
    (根据上下文设置进行舍入)
    方法的效果与 round(MathContext) 方法的效果相同
    BigDecimal round(MathContext mc)
    等同于BigDecimal plus(MathContext mc)
    image_5bdbee2a_17a
     

    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
    image_5bdbee2a_295a
    short shortValueExact()
    转换为 short
    如果此 BigDecimal 具有非零小数部分,或者超出 short 结果的可能范围
    抛出 ArithmeticException
    image_5bdbee2a_33f5
    int intValueExact()
    转换为 int
    如果此 BigDecimal 具有非零小数部分,或者超出 int 结果的可能范围
    抛出 ArithmeticException
    image_5bdbee2a_4e60
    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()]
    image_5bdbee2a_4d96
     

    移动小数点

    movePointLeft
    该值的小数点向左移动 n 位
    如果 n 为负数,则该调用等效于 movePointRight(-n)
    如果 n 为非负数,则调用仅将 n 添加到该标度
    返回的标度分别为:
    image_5bdbee2a_2cfe
    image_5bdbee2a_5e59
    movePointRight
    小数点向右移动 n 位
    如果 n 为负,则该调用等效于 movePointLeft(-n)
    如果 n 为非负数,则该调用仅从该标度减去 n
    返回的标度分别为:
    image_5bdbee2a_6782
    image_5bdbee2a_1089
     
    BigDecimal scaleByPowerOfTen(int n)
    返回其数值等于
    image_5bdbee2a_3358
    的BigDecimal

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

    总结

    BigDecimal虽然有诸多特性与特别,,但是本质仍旧是浮点数
    所以自然提供了浮点数相关的一些操作
    作为数值的基本运算方法都具备的
    需要注意的是构造方法之间的区别
    除非特别需要,否则不要直接使用double构造
    尽可能的使用String的形式
    对于valueOf方法也是具有缓存的
    BigDecimal是不可变的
    setScale的名字起的不太规范,容易让人迷惑,使用时要注意。
     
     
  • 相关阅读:
    css3 2D变形(transform)移动、缩放、旋转、倾斜
    鼠标经过图片会移动(css3过渡,overflow:hidden)
    CSS3 过渡 (transition )
    LICEcap – 灵活好用,GIF 屏幕录制工具
    CSS3新增选择器:伪元素选择器
    CSS3 新增选择器:伪类选择器和属性选择器
    HTML插入音频和视频:audio和video标签及其属性
    HTML5新增input标签属性
    HTML5新增常用标签
    通过EntityFramework来操作MySQL数据库
  • 原文地址:https://www.cnblogs.com/noteless/p/9896139.html
Copyright © 2011-2022 走看看