背景
在工作中发现BigDecimal的toString()会时不时出现科学计数法,为了了解其中的玄机,对BigDecimal的scale和precision进行了解释和总结
scale和precision
- scale,理解成比例尺,也代表小数点左移或右移的位数,scale<0代表左移, scale>0代表右移
- precision,理解成有效数字位数,即从左往右第一个不为0的数字开始计数,直到最后一位,其中所跨越的数字个数.特殊地,对于零,其有效位数是1
BigDecimal内部表示
在BigDecimal里,用integer,scale和precision来表示一个十进制数字
例如100表示为integer=100, scale=0, precision=2
同样100也可表示为integer=1, scale=-2, precision=1
再说scale
scale对数字的表示较为关键,以下是常见运算符对scale的影响,摘自BigDecimal的Javadoc
| Operation | Preferred Scale of Result |
|---|---|
| Add | max(addend.scale(), augend.scale()) |
| Subtract | max(minuend.scale(), subtrahend.scale()) |
| Multiply | multiplier.scale() + multiplicand.scale() |
| Divide | dividend.scale() - divisor.scale() |
| Square root | radicand.scale()/2 |
特别地,对于除法(divide)如果除不尽会抛出ArithmeticException异常, 因为无论scale多大也无法准确表示一个无限位的十进制数,此时需要去除尾数策略(RoundingMode).其有以下几种策略
| RoundingMode | 说明 |
|---|---|
| CEILING | 向正无限大方向舍入 |
| DOWN | 向零方向舍入 |
| FLOOR | 向负无限大方向舍入 |
| HALF_DOWN | 向最接近数字方向舍入,如果与两个相邻数字的距离相等,则向下舍入 |
| HALF_EVEN | 向最接近数字方向舍入,如果与两个相邻数字的距离相等,则向相邻的偶数舍入 |
| HALF_UP | 向最接近数字方向舍入,如果与两个相邻数字的距离相等,则向上舍入 |
| UNNECESSARY | 断言具有精确结果 |
带有rounding mode的除法,商的scale等同于被除数
- 例如
21/110,没有指定rounding, 会抛出rithmeticException - 还是
21/110,被除数的scale=0,指定rounding=CEILING, 商的scale=0,结果为1 - 还是
21/110,被除数的scale=10,指定rounding=CEILING,商的scale=10,结果为0.1909090910
回到toString()
toString()会在必要时采用科学计数法表示,规则如下
- scale=0, 即整数, 按实际表示,例如1230000,1111111
- scale<0, 即比例较大的数, 用科学计数法
- 例如
1/0.1=10, scale=-1, precision=1, 表示为1E+1
- 例如
- scale>0, 且
scale-Precision > 5, 使用科学计数法. 其他则直接表示- 例如
1.000000, scale=7 Precision=8, 表示为1.0000000 0.0000000, scale=7 Precision=1, 表示为0E-70.0000001, scale=7 Precision=1, 表示为1E-7
- 例如