com.feilong.core.lang.NumberUtil Maven / Gradle / Ivy
Show all versions of feilong Show documentation
/*
* Copyright (C) 2008 feilong
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.feilong.core.lang;
import static com.feilong.core.Validator.isNullOrEmpty;
import static com.feilong.core.bean.ConvertUtil.toBigDecimal;
import static com.feilong.core.lang.ObjectUtil.defaultIfNull;
import static java.math.BigDecimal.ZERO;
import static java.math.RoundingMode.HALF_UP;
import java.math.BigDecimal;
import java.math.RoundingMode;
import com.feilong.core.NumberPattern;
import com.feilong.core.Validate;
import com.feilong.core.text.NumberFormatUtil;
import com.feilong.lib.lang3.math.NumberUtils;
/**
* 处理{@link Integer},{@link Long},{@link BigDecimal}等数据类型.
*
* {@link RoundingMode#HALF_UP}与 {@link Math#round(double)}的区别:
*
*
*
* 注意{@link RoundingMode#HALF_UP} -2.5 会变成-3,如果是 {@link Math#round(double) Math.round(-2.5)} 会是-2
*
*
*
* {@link Double}转{@link BigDecimal}:
*
*
*
* 对于 double 转成 BigDecimal,推荐使用 BigDecimal.valueOf(double),不建议使用new BigDecimal(double),参见 JDK API
*
*
* - new BigDecimal(0.1) {@code ==>} 0.1000000000000000055511151231257827021181583404541015625
* - BigDecimal.valueOf(0.1) {@code ==>} 0.1
*
*
* 在《Effective Java 》这本书中也提到这个原则,float和double只能用来做科学计算或者是工程计算,在商业计算中我们要用 {@link java.math.BigDecimal}.
*
*
*
* JAVA 8种舍入法:
*
*
*
*
*
*
* 字段
* 说明
*
*
*
* {@link RoundingMode#UP}
* 远离零的方向舍入. 向绝对值最大的方向舍入,只要舍弃位非0即进位.
*
*
*
* {@link RoundingMode#DOWN}
* 靠近零的方向舍入,向绝对值最小的方向输入,所有的位都要舍弃,不存在进位情况.
*
*
*
* {@link RoundingMode#CEILING}
* 靠近正无穷方向舍入 向正无穷方向舍入 向正最大方向靠拢.
* 若是正数,舍入行为类似于ROUND_UP,
* 若为负数,舍入行为类似于ROUND_DOWN.
* Math.round()方法就是使用的此模式.
*
*
*
* {@link RoundingMode#FLOOR}
* 靠近负无穷方向舍入 向负无穷方向舍入 向负无穷方向靠拢.
* 若是正数,舍入行为类似于ROUND_DOWN;
* 若为负数,舍入行为类似于ROUND_UP.
*
*
*
* {@link RoundingMode#HALF_UP}
* 四舍五入,生活中的舍入方法.
* 最近数字舍入(5进).这是我们最经典的四舍五入.
*
*
*
* {@link RoundingMode#HALF_DOWN}
* 五舍六入,最近数字舍入(5舍). 在这里5是要舍弃的.
*
*
*
* {@link RoundingMode#HALF_EVEN}
* 精确舍入,银行家舍入法.
* 四舍六入;五分两种情况,如果前一位为奇数,则入位,否则舍去.
* 以下例子为保留小数点1位,那么这种舍入方式下的结果:
* {@code 1.15 返回 1.2} {@code 1.25 返回 1.2}
*
*
*
* {@link RoundingMode#UNNECESSARY}
* 无需舍入
*
*
*
*
*
* 关于 {@link RoundingMode#HALF_EVEN}:
*
*
*
*
* 该算法是由美国银行家提出了,主要用于修正采用上面四舍五入规则而产生的误差。如下:
*
* 舍去位的数值小于5时,直接舍去。
* 舍去位的数值大于5时,进位后舍去。
* 当舍去位的数值等于5时,
* 若5后面还有其他非0数值,则进位后舍去,
* 若5后面是0时,则根据5前一位数的奇偶性来判断,奇数进位,偶数舍去。
*
*
* 对于上面的规则我们举例说明:
*
*
* 11.556 = 11.56 ------六入
* 11.554 = 11.55 -----四舍
*
* 11.5551 = 11.56 -----五后有数进位
*
* 11.545 = 11.54 -----五后无数,若前位为偶数应舍去
* 11.555 = 11.56 -----五后无数,若前位为奇数应进位
*
*
*
*
*
*
* @author feilong
* @see Integer
* @see Long
* @see BigDecimal
* @see Number
* @see NumberPattern
* @see RoundingMode
* @see com.feilong.lib.lang3.math.NumberUtils
* @since 1.4.0
*/
@SuppressWarnings("squid:S1192") //String literals should not be duplicated
public final class NumberUtil{
/**
* 一,{@value}
.
*
* @see BigDecimal#ONE
* @see NumberUtils#INTEGER_ONE
* @since 1.10.7
*/
public static final int ONE = 1;
/**
* 十,{@value}
.
*
* @since 1.10.7
*/
public static final int TEN = 10;
/**
* 百,{@value}
.
*
* @since 1.10.7
*/
public static final int HUNDRED = 100;
/**
* 千,{@value}
.
*
* @since 1.10.7
*/
public static final int THOUSAND = 1000;
//---------------------------------------------------------------
/**
* 万,{@value}
.
*
* @since 1.10.7
*/
public static final int TEN_THOUSAND = 1_0000;
/**
* 十万,{@value}
.
*
* @since 1.10.7
*/
public static final int HUNDRED_THOUSAND = 10 * TEN_THOUSAND;
/**
* 百万,{@value}
.
*
* @since 1.10.7
*/
public static final int MILLION = 10 * HUNDRED_THOUSAND;
/**
* 千万,{@value}
.
*
* @since 1.10.7
*/
public static final int TEN_MILLION = 10 * MILLION;
//---------------------------------------------------------------
/**
* 亿, {@value}
.
*
* 说明:
*
*
* -
* {@link Integer#MAX_VALUE}:21_4748_3647 ,21亿, 注意使用的时候,超过最大值使用long来计算
*
*
*
*
* @since 1.10.7
*/
public static final int HUNDRED_MILLION = 10 * TEN_MILLION;
/**
* 十亿, {@value}
.
*
* 说明:
*
*
* -
* {@link Integer#MAX_VALUE}:21_4748_3647 ,21亿, 注意使用的时候,超过最大值使用long来计算
*
*
*
*
* @since 1.10.7
*/
public static final int BILLION = 10 * HUNDRED_MILLION;
/**
* 百亿, {@value}
.
*
* 说明:
*
*
* -
* {@link Integer#MAX_VALUE}:21_4748_3647 ,21亿, 注意使用的时候,超过最大值使用long来计算
*
*
*
*
* @since 1.10.7
*/
public static final long TEN_BILLION = (long) (BILLION) * 10;
//---------------------------------------------------------------
/** Don't let anyone instantiate this class. */
private NumberUtil(){
//AssertionError不是必须的. 但它可以避免不小心在类的内部调用构造器. 保证该类在任何情况下都不会被实例化.
//see 《Effective Java》 2nd
throw new AssertionError("No " + getClass().getName() + " instances for you!");
}
//---------------------------------------------------------------
/**
* 判断第1个数字数字值 one
是不是{@code > } (大于) 第2个数字数字值 two
.
*
* 原理:
*
*
* - 是将两个数组转成 BigDecimal 类型,并调用 {@link java.math.BigDecimal#compareTo(BigDecimal)} 比较大小
*
*
*
* 示例:
*
*
*
*
* NumberUtil.isGatherThan(0, 0) =false
*
* NumberUtil.isGatherThan(5, 4) =true
* NumberUtil.isGatherThan(5, 4L) =true
* NumberUtil.isGatherThan(5, 4.0f) =true
* NumberUtil.isGatherThan(5, 4.0d) =true
* NumberUtil.isGatherThan(5, toBigDecimal(4.0d)) =true
*
* NumberUtil.isGatherThan(toBigDecimal(5.0d), 4) =true
*
*
*
*
* @param one
* 第1个数字
* @param two
* 第2个数字
* @return 如果 one
大于 two
,那么返回true,否则返回false
* 如果 one
是null,抛出 {@link NullPointerException}
* 如果 two
是null,抛出 {@link NullPointerException}
* @since 1.10.7
*/
public static boolean isGatherThan(Number one,Number two){
return compare(one, two) == 1;
}
/**
* 判断第1个数字数字值 one
是不是{@code >= } (大于等于) 第2个数字数字值 two
.
*
* 原理:
*
*
* - 是将两个数组转成 BigDecimal 类型,并调用 {@link java.math.BigDecimal#compareTo(BigDecimal)} 比较大小
*
*
*
* 示例:
*
*
*
*
* NumberUtil.isGatherThanOrEquals(0, 0) =true
*
* NumberUtil.isGatherThanOrEquals(5, 4) =true
* NumberUtil.isGatherThanOrEquals(5, 4L) =true
* NumberUtil.isGatherThanOrEquals(5, 4.0f) =true
* NumberUtil.isGatherThanOrEquals(5, 4.0d) =true
* NumberUtil.isGatherThanOrEquals(5, toBigDecimal(4.0d)) =true
*
* NumberUtil.isGatherThanOrEquals(toBigDecimal(5.0d), 4) =true
*
*
*
*
* @param one
* 第1个数字
* @param two
* 第2个数字
* @return 如果 one
大于等于 two
,那么返回true,否则返回false
* 如果 one
是null,抛出 {@link NullPointerException}
* 如果 two
是null,抛出 {@link NullPointerException}
* @since 1.10.7
*/
public static boolean isGatherThanOrEquals(Number one,Number two){
int compareTo = compare(one, two);
return compareTo == 1 || compareTo == 0;
}
/**
* 判断第1个数字数字值 one
是不是{@code = } (等于) 第2个数字数字值 two
.
*
* 原理:
*
*
* - 是将两个数组转成 BigDecimal 类型,并调用 {@link java.math.BigDecimal#compareTo(BigDecimal)} 比较大小
*
*
*
* 示例:
*
*
*
*
* NumberUtil.isEquals(0, 0) =true
*
* NumberUtil.isEquals(5, 4) =false
* NumberUtil.isEquals(5, 5L) =true
* NumberUtil.isEquals(5, 5.0f) =true
* NumberUtil.isEquals(5, 5.0d) =true
* NumberUtil.isEquals(5, toBigDecimal(5.0d)) =true
*
* NumberUtil.isEquals(toBigDecimal(5.0d), 5) =true
*
*
*
*
* @param one
* 第1个数字
* @param two
* 第2个数字
* @return 如果 one
等于 two
,那么返回true,否则返回false.
* 如果 one
是null,抛出 {@link NullPointerException}
* 如果 two
是null,抛出 {@link NullPointerException}
* @since 1.10.7
*/
public static boolean isEquals(Number one,Number two){
return compare(one, two) == 0;
}
//---------------------------------------------------------------
/**
* 判断第1个数字数字值 one
是不是{@code < } (小于) 第2个数字数字值 two
.
*
* 原理:
*
*
* - 是将两个数组转成 BigDecimal 类型,并调用 {@link java.math.BigDecimal#compareTo(BigDecimal)} 比较大小
*
*
*
* 示例:
*
*
*
*
* NumberUtil.isLessThan(0, 0) =false
*
* NumberUtil.isLessThan(5, 4) =false
* NumberUtil.isLessThan(5, 5L) =false
* NumberUtil.isLessThan(5, 5.0f) =false
* NumberUtil.isLessThan(4, 5.0d) =true
* NumberUtil.isLessThan(5, toBigDecimal(5.0d)) =false
*
* NumberUtil.isLessThan(toBigDecimal(5.0d), 5) =false
*
*
*
*
* @param one
* 第1个数字
* @param two
* 第2个数字
* @return 如果 one
小于 two
,那么返回true,否则返回false.
* 如果 one
是null,抛出 {@link NullPointerException}
* 如果 two
是null,抛出 {@link NullPointerException}
* @since 1.10.7
*/
public static boolean isLessThan(Number one,Number two){
return compare(one, two) == -1;
}
/**
* 判断第1个数字数字值 one
是不是{@code <= } (小于等于) 第2个数字数字值 two
.
*
* 原理:
*
*
* - 是将两个数组转成 BigDecimal 类型,并调用 {@link java.math.BigDecimal#compareTo(BigDecimal)} 比较大小
*
*
*
* 示例:
*
*
*
*
* NumberUtil.isLessThanOrEquals(0, 0) =true
*
* NumberUtil.isLessThanOrEquals(5, 4) =false
* NumberUtil.isLessThanOrEquals(5, 5L) =true
* NumberUtil.isLessThanOrEquals(5, 5.0f) =true
* NumberUtil.isLessThanOrEquals(4, 5.0d) =true
* NumberUtil.isLessThanOrEquals(5, toBigDecimal(5.0d)) =true
*
* NumberUtil.isLessThanOrEquals(toBigDecimal(5.0d), 5) =true
*
*
*
*
* @param one
* 第1个数字
* @param two
* 第2个数字
* @return 如果 one
小于等于 two
,那么返回true,否则返回false
* 如果 one
是null,抛出 {@link NullPointerException}
* 如果 two
是null,抛出 {@link NullPointerException}
* @since 1.10.7
*/
public static boolean isLessThanOrEquals(Number one,Number two){
int compareTo = compare(one, two);
return compareTo == -1 || compareTo == 0;
}
//---------------------------------------------------------------
/**
* Compare.
*
* 说明:
*
*
* - 如果one == two ,返回 0
* - 如果one.equals(two) , 返回 0
* - 其余返回 toBigDecimal(one).compareTo(toBigDecimal(two))
*
*
*
* @param one
* the one
* @param two
* the two
* @return 如果 one
是null,抛出 {@link NullPointerException}
* 如果 two
是null,抛出 {@link NullPointerException}
* @since 1.10.7
*/
private static int compare(Number one,Number two){
Validate.notNull(one, "one can't be null!");
Validate.notNull(two, "two can't be null!");
//---------------------------------------------------------------
if (one == two){
return 0;
}
return one.equals(two) ? 0 : toBigDecimal(one).compareTo(toBigDecimal(two));
}
//---------------------------------------------------------------
// [start]Divide
/**
* 获得除法结果one/two
,四舍五入{@link RoundingMode#HALF_UP},小数位数 scale
指定.
*
* 示例:
*
*
*
*
* NumberUtil.getDivideValue(0, 2, 0) = toBigDecimal(0)
* NumberUtil.getDivideValue(6, 4, 0) = toBigDecimal(2)
* NumberUtil.getDivideValue(10, 3, 2) = toBigDecimal(3.33)
* NumberUtil.getDivideValue(5, 3, 2) = toBigDecimal(1.67)
*
*
*
*
* @param one
* 除数
* @param two
* 被除数,自动转成{@link BigDecimal}做除法运算
* @param scale
* 标度,小数的位数,四舍五入,用于 {@link java.math.BigDecimal#setScale(int, RoundingMode)}
* 如果为零或正数,则标度是小数点后的位数。
* 如果为负数,则将该数的非标度值乘以 10 的负 scale 次幂 (通常情况用不到负数的情况)
* @return 如果 one
是 null,抛出 {@link NullPointerException}
* 如果 two
是 null,抛出 {@link NullPointerException}
* 如果 two
是 0,抛出 {@link IllegalArgumentException}
* 否则转换成{@link BigDecimal} 返回除法结果one/two,四舍五入 {@link RoundingMode#HALF_UP},小数位数 scale
指定
* @see JAVA 8种舍入法
* @see java.math.RoundingMode#HALF_UP
* @see java.math.BigDecimal#ROUND_HALF_UP
* @see #getDivideValue(Number, Number, int, RoundingMode)
* @since 1.5.5
*/
public static BigDecimal getDivideValue(Number one,Number two,int scale){
return getDivideValue(one, two, scale, HALF_UP);
}
/**
* 获得除法结果one/two
,指定舍入方式 roundingMode
以及 小数位数 scale
.
*
* 示例:
*
*
*
*
* NumberUtil.getDivideValue(0, 2, 0,RoundingMode.HALF_UP) = 0
* NumberUtil.getDivideValue(6, 4, 0,RoundingMode.HALF_UP) = 2
* NumberUtil.getDivideValue(10, 3, 2,RoundingMode.HALF_UP) = 3.33
* NumberUtil.getDivideValue(5, 3, 2,RoundingMode.HALF_UP) = 1.67
*
*
*
*
* @param one
* 除数
* @param two
* 被除数,自动转成{@link BigDecimal}做除法运算
* @param scale
* 标度,小数的位数,四舍五入,用于 {@link java.math.BigDecimal#setScale(int, RoundingMode)}
* 如果为零或正数,则标度是小数点后的位数。
* 如果为负数,则将该数的非标度值乘以 10 的负 scale 次幂 (通常情况用不到负数的情况)
* @param roundingMode
* 舍入法 {@link RoundingMode}
* @return 如果 one
是 null,抛出 {@link NullPointerException}
* 如果 two
是 null,抛出 {@link NullPointerException}
* 如果 two
是 0,抛出 {@link IllegalArgumentException}
* 否则转换成{@link BigDecimal} 返回除法结果one/two,依据舍入法 roundingMode
,小数位数 scale
指定
* @see JAVA 8种舍入法
* @see java.math.BigDecimal#divide(BigDecimal, int, RoundingMode)
* @since 1.5.5
*/
public static BigDecimal getDivideValue(Number one,Number two,int scale,RoundingMode roundingMode){
Validate.notNull(one, "one can't be null!");
Validate.notNull(two, "two can't be null!");
BigDecimal divisor = toBigDecimal(two);
Validate.isTrue(!divisor.equals(ZERO), "two can't be zero!");
// 不能直接one.divide(two),应该指定scale和roundingMode,保证对于无限小数有足够的范围来表示结果.
// 避免 exception:Non-terminating decimal expansion; no exact representable decimal result (无法结束的除法表达式;没有精确的除结果)
return toBigDecimal(one).divide(divisor, scale, roundingMode);
}
// [end]
// [start]Multiply
/**
* 将第一个数字 one
和第二个数字 two
相乘,指定精度 scale
, 返回{@link BigDecimal}.
*
* 示例:
*
*
*
*
* NumberUtil.getMultiplyValue(5, 2, 5) = toBigDecimal("10.00000")
* NumberUtil.getMultiplyValue(new BigDecimal(6.25), 1.17, 5) = toBigDecimal("7.31250")
* NumberUtil.getMultiplyValue(9.86, 100, 0) = toBigDecimal("986")
*
*
*
*
* @param one
* 乘数
* @param two
* 被乘数
* @param scale
* 标度,小数的位数,四舍五入,用于 {@link java.math.BigDecimal#setScale(int, RoundingMode)}
* 如果为零或正数,则标度是小数点后的位数。
* 如果为负数,则将该数的非标度值乘以 10 的负 scale 次幂 (通常情况用不到负数的情况)
* @return 如果 one
是 null,抛出 {@link NullPointerException}
* 如果 two
是 null,抛出 {@link NullPointerException}
* 否则 convert to {@link BigDecimal} and multiply each other
* @see #setScale(Number, int)
* @since 1.5.5
*/
public static BigDecimal getMultiplyValue(Number one,Number two,int scale){
Validate.notNull(one, "one can't be null!");
Validate.notNull(two, "two can't be null!");
//默认返回的精度: (this.scale() + multiplicand.scale()).
BigDecimal multiplyValue = toBigDecimal(one).multiply(toBigDecimal(two));
return setScale(multiplyValue, scale);
}
// [end]
// [start]Add
/**
* 所有数加起来.
*
*
* 关于精度: 返回结果的精度等于精度最大的元素的精度,比如 NumberUtil.getAddValue(2, 4, 5.00000) = 11.00000
*
*
* 说明:
*
*
* - 支持跳过null 元素相加 (since 1.11.5)
* - 但是如果所有元素都是null ,将会抛出 {@link IllegalArgumentException}
*
*
*
* 示例:
*
*
*
*
* NumberUtil.getAddValue(2, 4, 5) = 11
* NumberUtil.getAddValue(2, 4, 5.00000) = 11.00000
* NumberUtil.getAddValue(new BigDecimal(6), 5) = 11
* NumberUtil.getAddValue(new BigDecimal(6), null) = 6
*
*
*
*
* @param numbers
* the numbers
* @return 如果 numbers
是null,抛出 {@link NullPointerException}
* 如果 numbers
是empty,抛出 {@link IllegalArgumentException}
* 如果所有元素都是null,抛出 {@link IllegalArgumentException}
* 否则将每个元素(跳过 null元素)转换成{@link BigDecimal},并进行累加操作
* @since 1.5.5
* @since 1.11.5 allow null element
*/
public static BigDecimal getAddValue(Number...numbers){
Validate.notEmpty(numbers, "numbers can't be null/empty!");
//---------------------------------------------------------------
if (isAllElementNull(numbers)){
throw new IllegalArgumentException("can not all numbers is null!");
}
//---------------------------------------------------------------
BigDecimal sum = ZERO;
for (Number number : numbers){
if (null == number){
continue;
}
sum = sum.add(toBigDecimal(number));
}
return sum;
}
/**
* 是否所有元素是null.
*
* @param numbers
* the numbers
* @return true, if is all null
* @since 1.11.5
*/
private static boolean isAllElementNull(Number...numbers){
for (Number number : numbers){
if (null != number){
return false;
}
}
return true;
}
//---------------------------------------------------------------
/**
* 所有数相减.
*
*
* 关于精度: 返回结果的精度等于精度最大的元素的精度,比如 NumberUtil.getSubtractValue(1000, 99.5, 99.0000) = 801.5000
*
*
* 说明:
*
*
* - 支持跳过null 元素相加 (since 1.11.5)
*
*
*
* 示例:
*
*
*
*
* NumberUtil.getSubtractValue(0, 2, 3) = -5
* NumberUtil.getSubtractValue(0,null) = 0
* NumberUtil.getSubtractValue(0, new Integer[5]) = 0
* NumberUtil.getSubtractValue(2, 1.1) = 0.9
* NumberUtil.getSubtractValue(1000, 99.5, 99.0) = 801.5
* NumberUtil.getSubtractValue(1000, 50, null) = 950
* NumberUtil.getSubtractValue(-1000, -50, 100) = -1050
*
* NumberUtil.getSubtractValue(null, 5) // NullPointerException
*
*
*
*
* @param beSubtractedValue
* 被减数,如 100-10-5, 其中的100 就是被减数
* @param subtractions
* 减数,如 100-10-5, 其中的10 和5 就是减数
* @return 如果 beSubtractedValue
是null,抛出 {@link NullPointerException}
* 如果 subtractions
是null或者是empty,直接将beSubtractedValue
转成BigDecimal 并返回
* 循环 subtractions
,使用 beSubtractedValue
减去元素的值,如果循环的原始null,跳过这次减法
* @since 1.10.6
*/
public static BigDecimal getSubtractValue(Number beSubtractedValue,Number...subtractions){
Validate.notNull(beSubtractedValue, "beSubtractedValue can't be null/empty!");
//---------------------------------------------------------------
BigDecimal result = toBigDecimal(beSubtractedValue);
if (isNullOrEmpty(subtractions)){
return result;
}
//---------------------------------------------------------------
for (Number subtraction : subtractions){
if (null == subtraction){//跳过 null 元素
continue;
}
result = result.subtract(toBigDecimal(subtraction));
}
return result;
}
/**
* 数相减.
*
* 示例:
*
*
*
*
* NumberUtil.getSubtractValue(null, 2, 2) = NullPointerException
*
* NumberUtil.getSubtractValue(0, 2, 0) = -2
* NumberUtil.getSubtractValue(0, 2, 2) = -2.00
*
* NumberUtil.getSubtractValue(0,null,0) = 0
* NumberUtil.getSubtractValue(0,null,2) = 0.00
*
*
*
*
* @param beSubtractedValue
* 被减数,如 100-10, 其中的100 就是被减数
* @param subtraction
* 减数,如 100-10, 其中的10 就是减数
* @param scale
* 设置精度
* 说明:
*
*
*
* - 被舍入部分{@code >=}0.5向上,否则向下
* - {@link RoundingMode#HALF_UP} -2.5 会变成-3,如果是 Math.round(-2.5) 会是-2
*
* -
* 不要直接使用 jdk 原生的 setScale方法, 比如
*
*
* //异常,BigDecimal对象的小数位超出了保留的小数位,且保留的小数位后面出现非0的数值,会抛出 Rounding necessary 异常
* BigDecimal bigDecimal4 = new BigDecimal("1.9395");
* bigDecimal4.setScale(2);
*
*
*
* @return 如果 beSubtractedValue
是null,抛出 {@link NullPointerException}
* 如果 subtraction
是null,直接将beSubtractedValue
转成BigDecimal设置精度并返回
* @since 3.5.0
*/
public static BigDecimal getSubtractValueWithScale(Number beSubtractedValue,Number subtraction,int scale){
BigDecimal subtractValue = getSubtractValue(beSubtractedValue, subtraction);
return setScale(subtractValue, scale);
}
// [end]
/**
* 将数字 value
按照指定的格式 numberPattern
格式成字符串 .
*
*
* 调用 {@link NumberFormatUtil#format(Number, String, RoundingMode)},当遇到需要舍入的时候,使用常用的 {@link RoundingMode#HALF_UP}
*
*
* 关于参数 value
:
*
*
*
* 请尽量传递Integer,Long,BigDecimal,而不要使用 float,double等浮点类型,否则可能结果不准确,特别是jdk8以下的版本,具体参见
* NumberFormatUtilTest 在 jdk8 下面测试不通过
*
*
*
*
* 示例:
*
*
* //将数字转成百分数字符串,不带小数点
* NumberUtil.toString(0.24f, NumberPattern.PERCENT_WITH_NOPOINT) = 24%
*
* //将数字转成百分数字符串,带两位小数点
* NumberUtil.toString(0.24f, NumberPattern.PERCENT_WITH_2POINT) = 24.00%
*
* NumberUtil.toString(toBigDecimal(1.15), "#####.#") = 1.2
* NumberUtil.toString(toBigDecimal(1.25), "#####.#") = 1.3
* NumberUtil.toString(toBigDecimal(1.251), "#####.#") = 1.3
*
* NumberUtil.toString(toBigDecimal(-1.15), "#####.#") = -1.2
* NumberUtil.toString(toBigDecimal(-1.25), "#####.#") = -1.3
* NumberUtil.toString(toBigDecimal(-1.251), "#####.#") = -1.3
*
* NumberUtil.toString(toBigDecimal(25.5), "RP #####") = RP 26
*
*
* @param value
* 值
* @param numberPattern
* 转成字符串格式 {@link NumberPattern}
* @return 如果 value
是null,抛出 {@link NullPointerException}
* 如果 toStringPattern
是null,抛出 {@link NullPointerException}
* 如果 toStringPattern
是blank,抛出 {@link IllegalArgumentException}
* @see NumberFormatUtil#format(Number, String, RoundingMode)
*/
public static String toString(Number value,String numberPattern){
return NumberFormatUtil.format(value, numberPattern, HALF_UP);
}
//---------------------------------------------------------------
/**
* 计算进度(当前量 current
/总量 total
,使用百分比两位小数点 {@link NumberPattern#PERCENT_WITH_2POINT} 转成指定的字符串格式.
*
*
* 常用于友好的显示 下载进度,执行进度
等等场景
*
*
* 示例:
*
*
*
*
*
* NumberUtil.getProgress(5, 5) = "100.00%"
* NumberUtil.getProgress(2, 3) = "66.67%"
*
*
*
*
*
* @param current
* 当前量
* @param total
* 总量
* @return 如果 current
是null,抛出 {@link NullPointerException}
* 如果 total
是null,抛出 {@link NullPointerException}
* 如果 {@code current <= 0},抛出 {@link IllegalArgumentException}
* 如果 {@code total <= 0},抛出 {@link IllegalArgumentException}
* 如果 {@code current > total},抛出 {@link IllegalArgumentException}
* @see NumberPattern
* @see #getDivideValue(Number, Number, int)
* @see #toString(Number, String)
* @since 3.1.1
*/
public static String getProgress(Number current,Number total){
return getProgress(current, total, NumberPattern.PERCENT_WITH_2POINT);
}
/**
* 计算进度(当前量 current
/总量 total
,然后转成指定的字符串格式 numberPattern
).
*
*
* 常用于友好的显示 下载进度,执行进度
等等场景
*
*
* 示例:
*
*
*
*
*
* NumberUtil.getProgress(5, 5, NumberPattern.PERCENT_WITH_NOPOINT) = "100%"
* NumberUtil.getProgress(2, 3, NumberPattern.PERCENT_WITH_1POINT) = "66.7%"
*
*
*
*
*
* @param current
* 当前量
* @param total
* 总量
* @param numberPattern
* 转成字符串格式 {@link NumberPattern}
* @return 如果 current
是null,抛出 {@link NullPointerException}
* 如果 total
是null,抛出 {@link NullPointerException}
* 如果 {@code current <= 0},抛出 {@link IllegalArgumentException}
* 如果 {@code total <= 0},抛出 {@link IllegalArgumentException}
* 如果 {@code current > total},抛出 {@link IllegalArgumentException}
* 如果 toStringPattern
是null,抛出 {@link NullPointerException}
* 如果 toStringPattern
是blank,抛出 {@link IllegalArgumentException}
* @see NumberPattern
* @see #getDivideValue(Number, Number, int)
* @see #toString(Number, String)
* @since 1.0.7
*/
public static String getProgress(Number current,Number total,String numberPattern){
Validate.notNull(current, "current can't be null/empty!");
Validate.notNull(total, "total can't be null/empty!");
Validate.isTrue(current.intValue() > 0, "current can not <=0");
Validate.isTrue(total.intValue() > 0, "total can not <=0");
Validate.isTrue(current.doubleValue() <= total.doubleValue(), "current can not > total");
// XXX scale = 8不是最优方案
int scale = 8;
BigDecimal divideValue = getDivideValue(current, total, scale);
return toString(divideValue, numberPattern);
}
//********************setScale********************************************************
/**
* 使用四舍五入 {@link RoundingMode#HALF_UP} 设置小数点位数.
*
* 示例:
*
*
*
*
* NumberUtil.setScale(5, 5) = toBigDecimal("5.00000")
* NumberUtil.setScale(5.2, 3) = toBigDecimal("5.200")
* NumberUtil.setScale(5.26, 1) = toBigDecimal("5.3")
* NumberUtil.setScale(-5.26, 1) = toBigDecimal("-5.3")
*
* NumberUtil.setScale(-0, 1) = toBigDecimal("0.0")
*
* NumberUtil.setScale(0, 1) = toBigDecimal("0.0")
* NumberUtil.setScale(0, 2) = toBigDecimal("0.00")
*
*
*
*
* 说明:
*
*
*
* - 被舍入部分{@code >=}0.5向上,否则向下
* - {@link RoundingMode#HALF_UP} -2.5 会变成-3,如果是 Math.round(-2.5) 会是-2
*
* -
* 不要直接使用 jdk 原生的 setScale方法, 比如
*
*
* //异常,BigDecimal对象的小数位超出了保留的小数位,且保留的小数位后面出现非0的数值,会抛出 Rounding necessary 异常
* BigDecimal bigDecimal4 = new BigDecimal("1.9395");
* bigDecimal4.setScale(2);
*
*
*
*
*
*
* @param value
* number
* @param scale
* 标度,小数的位数,四舍五入,用于 {@link java.math.BigDecimal#setScale(int, RoundingMode)}
* 如果为零或正数,则标度是小数点后的位数。
* 如果为负数,则将该数的非标度值乘以 10 的负 scale 次幂 (通常情况用不到负数的情况)
* @return 如果 value
是null,抛出 {@link NullPointerException}
* @see JAVA 8种舍入法
* @see java.math.RoundingMode#HALF_UP
* @see java.math.BigDecimal#ROUND_HALF_UP
* @since 1.8.6
*/
public static BigDecimal setScale(Number value,int scale){
return setScale(value, scale, HALF_UP);
}
/**
* 使用roundingMode
来设置小数点位数.
*
* 示例:
*
*
*
*
* NumberUtil.setScale(5, 5,HALF_UP) = toBigDecimal("5.00000")
* NumberUtil.setScale(5.2, 3,HALF_UP) = toBigDecimal("5.200")
* NumberUtil.setScale(5.26, 1,HALF_UP) = toBigDecimal("5.3")
* NumberUtil.setScale(-5.26, 1,HALF_UP) = toBigDecimal("-5.3")
*
* NumberUtil.setScale(-0, 1,HALF_UP) = toBigDecimal("0.0")
*
* NumberUtil.setScale(0, 1,HALF_UP) = toBigDecimal("0.0")
* NumberUtil.setScale(0, 2,HALF_UP) = toBigDecimal("0.00")
*
* NumberUtil.setScale(5, 5,null) = toBigDecimal("5.00000")
* NumberUtil.setScale(5.2, 3,null) = toBigDecimal("5.200")
* NumberUtil.setScale(5.26, 1,null) = toBigDecimal("5.3")
* NumberUtil.setScale(-5.26, 1,null) = toBigDecimal("-5.3")
*
* NumberUtil.setScale(-0, 1,null) = toBigDecimal("0.0")
*
* NumberUtil.setScale(0, 1,null) = toBigDecimal("0.0")
* NumberUtil.setScale(0, 2,null) = toBigDecimal("0.00")
*
*
*
*
* 说明:
*
*
*
* - 被舍入部分{@code >=}0.5向上,否则向下
* - {@link RoundingMode#HALF_UP} -2.5 会变成-3,如果是 Math.round(-2.5) 会是-2
*
* -
* 不要直接使用 jdk 原生的 setScale方法, 比如
*
*
* //异常,BigDecimal对象的小数位超出了保留的小数位,且保留的小数位后面出现非0的数值,会抛出 Rounding necessary 异常
* BigDecimal bigDecimal4 = new BigDecimal("1.9395");
* bigDecimal4.setScale(2);
*
*
*
*
*
*
* @param value
* number
* @param scale
* 标度,小数的位数,四舍五入,用于 {@link java.math.BigDecimal#setScale(int, RoundingMode)}
* 如果为零或正数,则标度是小数点后的位数。
* 如果为负数,则将该数的非标度值乘以 10 的负 scale 次幂 (通常情况用不到负数的情况)
* @param roundingMode
* 舍入模式{@link RoundingMode},如果 为null,使用常用的 {@link RoundingMode#HALF_UP}
* @return 如果 value
是null,抛出 {@link NullPointerException}
* 如果 roundingMode
是null,使用常用的 {@link RoundingMode#HALF_UP}
* @see JAVA 8种舍入法
* @since 1.8.6
*/
public static BigDecimal setScale(Number value,int scale,RoundingMode roundingMode){
Validate.notNull(value, "value can't be null!");
return toBigDecimal(value).setScale(scale, defaultIfNull(roundingMode, HALF_UP));
}
}