【实际开发11】- 统计 / 科学计算 - 2

目录

5. BigDecimal 总结 - ★★★

1. BigDecimal 为不可变对象 , 每次“操作”都会返回新对象

1. BigDecimal 源码 API【概念】

2. [精度] precision、[非标度值] unscale、[标度] scale

1. BigD~支持任意精度 , 任意长度的浮点数运算 ( 建议设精确度 )

3. 强制设置[标度] scale

4. 舍入 : 详细示例

1. 舍入方式值 ( 8 种 )

2. 不同舍入模式下的舍入操作汇总

5. MathContext 示例

6. equals 和 sort

7. 综合示例

1. BigDecimalTest.java


5. BigDecimal 总结 - ★★★

BigDecimal总结_gqltt的博客-CSDN博客_bigdecimal的decimal32


1. BigDecimal 为不可变对象 , 每次“操作”都会返回新对象


1. BigDecimal 源码 API【概念】

通过查看 BigDecimal 源码API所知:

java.math.BigDecimal

不可变的、任意精度的有符号十进制数。BigDecimal 由任意精度的整数非标度值和32位的整数标度(scale)组成。

如果为零或正数 , 则标度是小数点后的位数。如果为负数 , 则将该数的非标度值乘以10的负scale次幂。

因此 , BigDecimal 表示的数值是 ( unscaledValue × 10-scale ) 。

与之相关的还有两个类:

java.math.MathContext:

该对象是封装上下文设置的不可变对象 , 它描述数字运算符的某些规则 , 如数据的精度 , 舍入方式等。

java.math.RoundingMode:

这是一种枚举类型 , 定义了很多常用的数据舍入方式。

这个类用起来还是很比较复杂的 , 原因在于舍入模式 , 数据运算规则太多太多 ,

不是数学专业出身的人看着中文API都难以理解 , 这些规则在实际中使用的时候在翻阅都来得及。

应用场景:

在银行、帐户、计费等领域 , BigDecimal 提供了精确的数值计算。其中8种舍入方式值得掌握。


2. [精度] precision、[非标度值] unscale、[标度] scale

//-------- 正数的[精度]precision、[非标度值]unscale、[标度]scale

// 0 precision=1 , unscale=0 , scale=0
BigDecimal tmp = new BigDecimal("0");
System.out.println( "0 precision=" + tmp.precision() +" , unscale=" + tmp.unscaledValue()+ " , scale=" + tmp.scale() );
 
tmp = new BigDecimal("0.0");
//0.0 precision=1 , unscale=0 , scale=1
System.out.println( "0.0 precision=" + tmp.precision() +" , unscale=" + tmp.unscaledValue()+ " , scale=" + tmp.scale());
 
tmp = new BigDecimal("1");
//1 precision=1 , unscale=1 , scale=0
System.out.println( "1 precision=" + tmp.precision() +" , unscale=" + tmp.unscaledValue()+ " , scale=" + tmp.scale());
 
tmp = new BigDecimal("1.0");
//1.0 precision=2 , unscale=10 , scale=1
System.out.println( "1.0 precision=" + tmp.precision() +" , unscale=" + tmp.unscaledValue()+ " , scale=" + tmp.scale());
 
tmp = new BigDecimal("0.1");
//0.1 precision=1 , unscale=1 , scale=1
System.out.println( "0.1 precision=" + tmp.precision() +" , unscale=" + tmp.unscaledValue()+ " , scale=" + tmp.scale());
 
tmp = new BigDecimal("122.000");
//122.000 precision=6 , unscale=122000 , scale=3
System.out.println( "122.000 precision=" + tmp.precision() +" , unscale=" + tmp.unscaledValue()+ " , scale=" + tmp.scale());
 

 
//----------负数的[精度]precision、[非标度值]unscale、[标度]scale

//-0 precision=1 , unscale=0 , scale=0
tmp = new BigDecimal("-0");
System.out.println( "-0 precision=" + tmp.precision() +" , unscale=" + tmp.unscaledValue()+ " , scale=" + tmp.scale() );
 
tmp = new BigDecimal("-0.0");
//-0.0 precision=1 , unscale=0 , scale=1
System.out.println( "-0.0 precision=" + tmp.precision() +" , unscale=" + tmp.unscaledValue()+ " , scale=" + tmp.scale());
 
tmp = new BigDecimal("-1");
//-1 precision=1 , unscale=-1 , scale=0
System.out.println( "-1 precision=" + tmp.precision() +" , unscale=" + tmp.unscaledValue()+ " , scale=" + tmp.scale());
 
tmp = new BigDecimal("-1.0");
//-1.0 precision=2 , unscale=-10 , scale=1
System.out.println( "-1.0 precision=" + tmp.precision() +" , unscale=" + tmp.unscaledValue()+ " , scale=" + tmp.scale());
 
tmp = new BigDecimal("-0.1");
//-0.1 precision=1 , unscale=-1 , scale=1
System.out.println( "-0.1 precision=" + tmp.precision() +" , unscale=" + tmp.unscaledValue()+ " , scale=" + tmp.scale());
 
tmp = new BigDecimal("-122.000");
//-122.000 precision=6 , unscale=-122000 , scale=3
System.out.println( "-122.000 precision=" + tmp.precision() +" , unscale=" + tmp.unscaledValue()+ " , scale=" + tmp.scale());


1. BigD~支持任意精度 , 任意长度的浮点数运算 ( 建议设精确度 )

BigDecimal 支持任意精度 , 任意长度的浮点数运算 , 但在运算的时候最好设置各个操作数的小数精确度 , 特别是除法。

结果需要保留几位小数 , 如果没有设置除法的操作数的小数精确度 , 计算结果的精确度就会和操作数中最低精确度一致 , 导致计算结果不正确 ,

如下例子:

    String a = "1";
    String b = "4.56";
    BigDecimal aBD = new BigDecimal(a);
    BigDecimal bBD = new BigDecimal(b);
    BigDecimal resultBD = aBD.divide(bBD).setScale(3 ,  java.math.BigDecimal.ROUND_HALF_UP);

3是保留小数 , ROUND_HALF_UP是四舍五入 , 此参数的其他值请查看文章:http://www.bdqn.cn/news/201311/11834.shtml

这个例子你期望的是0.219 , 但是你实际会得到0。

为什么呢?

这就是保留精确度问题了 , a是一个整数 , 运算时把结果当作整数取了 , 那就是0了。

所以 , 应该按下面的运算:

    String a = "1";
    String b = "4.56";
    BigDecimal aBD = new BigDecimal(a).setScale(3);
    BigDecimal bBD = new BigDecimal(b).setScale(3);
    BigDecimal resultBD = aBD.divide(bBD).setScale(3 ,  java.math.BigDecimal.ROUND_HALF_UP);

这样 , 你就会得到一个正确的值了。

还有一个需要注意的点 , 计算结果 , 如例子中的resultBD一定要设置其setScale的第二个参数 , 不然会报错。

如果计算结果没有按某个方式进行截断 , 那么机器就不知道如何去取这个结果了 , 因此报错。


3. 强制设置[标度] scale

//强制设置[标度]scale

//----scale默认的0设置为3
BigDecimal de1 = new BigDecimal("125");
System.out.println( "默认scale为0:" + de1 );
System.out.println( "强制设置scale为3:" + de1.setScale(3) );
 
//----scale由初始的2设置为5
de1 = new BigDecimal("28.02");
System.out.println( "初始scale为2:" + de1 );
System.out.println( "强制设置scale为5:" + de1.setScale(5) );
 
//----scale由初始的7设置为2
de1 = new BigDecimal("177.1234567");
System.out.println( "初始scale为7:" + de1 );

try{
	//精度由大变小(7->2)必须设置舍入规则
	System.out.println( "强制设置scale为2:" + de1.setScale(2) );
}catch(Exception e){
	System.out.println( e.getMessage() );
}
System.out.println( "强制设置scale为2:" + de1.setScale(2 ,  RoundingMode.HALF_UP) );


4. 舍入 : 详细示例

BigDecimal b1 = new BigDecimal("1");
BigDecimal b2 = new BigDecimal("2");
BigDecimal b3 = new BigDecimal("3");
//按指定精度 , 向上0.333∞ -> 1
System.out.println("ROUND_CEILING:1/3 = " + b1.divide(b3 ,  RoundingMode.CEILING) );
//按指定精度 , 向上0.333∞ -> 1
System.out.println("ROUND_UP:1/3 = " + b1.divide(b3 ,  RoundingMode.UP) );
 
//按指定精度 , 向下0.333∞ -> 0
System.out.println("ROUND_DOWN:1/3 = " + b1.divide(b3 ,  RoundingMode.DOWN) );
//按指定精度 , 向下0.333∞ -> 0
System.out.println("ROUND_FLOOR:1/3 = " + b1.divide(b3 ,  RoundingMode.FLOOR) );
 
//按指定精度 , 趋近最近的数 , 0.333∞ -> 0
System.out.println("ROUND_HALF_DOWN:1/3 = " + b1.divide(b3 ,  RoundingMode.HALF_DOWN) );
//按指定精度 , 趋近最近的数 , 0.333∞ -> 0
System.out.println("ROUND_HALF_UP:1/3 = " + b1.divide(b3 ,  RoundingMode.HALF_UP) );
 
//按指定精度 , 趋近最近的数 , 0.5向下 0.5-> 0
System.out.println("ROUND_HALF_DOWN:1/2 = " + b1.divide(b2 ,  RoundingMode.HALF_DOWN) );
//按指定精度 , 趋近最近的数 , 0.5向上 0.5-> 1
System.out.println("ROUND_HALF_UP:1/2 = " + b1.divide(b2 ,  RoundingMode.HALF_UP) );
 
//按指定精度 , 趋近最近的数 , 0.333∞ -> 1
System.out.println("ROUND_HALF_DOWN:2/3 = " + b2.divide(b3 ,  RoundingMode.HALF_DOWN) );
//按指定精度 , 趋近最近的数 , 0.333∞ -> 1
System.out.println("ROUND_HALF_UP:2/3 = " + b2.divide(b3 ,  RoundingMode.HALF_UP) );
 
 
//按指定精度 , 趋近最近的数 , 0.5 -> 偶数
//ROUND_HALF_EVEN:1/3 = 0
System.out.println("ROUND_HALF_EVEN:1/3 = " + b1.divide(b3 ,  RoundingMode.HALF_EVEN) );
//ROUND_HALF_EVEN:1/2 = 0
System.out.println("ROUND_HALF_EVEN:1/2 = " + b1.divide(b2 ,  RoundingMode.HALF_EVEN) );
//ROUND_HALF_EVEN:2/3 = 1
System.out.println("ROUND_HALF_EVEN:2/3 = " + b2.divide(b3 ,  RoundingMode.HALF_EVEN) );
 
//明确知道结果 , 否则抛异常
System.out.println("ROUND_UNNECESSARY:2 = " + b2.setScale(2 ,  RoundingMode.UNNECESSARY));
try{
	//计算中的结果无法使用:ROUND_UNNECESSARY
	System.out.println("ROUND_UNNECESSARY:1/2 = " + b1.divide(b2 ,  RoundingMode.UNNECESSARY) );
}catch( Exception e ){
	//Rounding necessary
	System.out.println( e.getMessage() );
}


1. 舍入方式值 ( 8 种 )

1、ROUND_UP

舍入远离零的舍入模式。

在丢弃非零部分之前始终增加数字(始终对非零舍弃部分前面的数字加1)。

注意 , 此舍入模式始终不会减少计算值的大小。

2、ROUND_DOWN

接近零的舍入模式。

在丢弃某部分之前始终不增加数字(从不对舍弃部分前面的数字加1 , 即截短)。

注意 , 此舍入模式始终不会增加计算值的大小。

3、ROUND_CEILING

接近正无穷大的舍入模式。

如果 BigDecimal 为正 , 则舍入行为与 ROUND_UP 相同;

如果为负 , 则舍入行为与 ROUND_DOWN 相同。

注意 , 此舍入模式始终不会减少计算值。

4、ROUND_FLOOR

接近负无穷大的舍入模式。

如果 BigDecimal 为正 , 则舍入行为与 ROUND_DOWN 相同;

如果为负 , 则舍入行为与 ROUND_UP 相同。

注意 , 此舍入模式始终不会增加计算值。

5、ROUND_HALF_UP

向“最接近的”数字舍入 , 如果与两个相邻数字的距离相等 , 则为向上舍入的舍入模式。

如果舍弃部分 >= 0.5 , 则舍入行为与 ROUND_UP 相同;否则舍入行为与 ROUND_DOWN 相同。

注意 , 这是我们大多数人在小学时就学过的舍入模式(四舍五入)。

6、ROUND_HALF_DOWN

向“最接近的”数字舍入 , 如果与两个相邻数字的距离相等 , 则为上舍入的舍入模式。

如果舍弃部分 > 0.5 , 则舍入行为与 ROUND_UP 相同;否则舍入行为与 ROUND_DOWN 相同(五舍六入)。

7、ROUND_HALF_EVEN

向“最接近的”数字舍入 , 如果与两个相邻数字的距离相等 , 则向相邻的偶数舍入。

如果舍弃部分左边的数字为奇数 , 则舍入行为与 ROUND_HALF_UP 相同;

如果为偶数 , 则舍入行为与 ROUND_HALF_DOWN 相同。

注意 , 在重复进行一系列计算时 , 此舍入模式可以将累加错误减到最小。

此舍入模式也称为“银行家舍入法” , 主要在美国使用。四舍六入 , 五分两种情况。

如果前一位为奇数 , 则入位 , 否则舍去。

以下例子为保留小数点1位 , 那么这种舍入方式下的结果。

1.15>1.2 1.25>1.2

8、ROUND_UNNECESSARY

断言请求的操作具有精确的结果 , 因此不需要舍入。

如果对获得精确结果的操作指定此舍入模式 , 则抛出 ArithmeticException。


2. 不同舍入模式下的舍入操作汇总

根据给定的舍入模式将输入数字舍入为一位数的结果 
输入数字 UP DOWN CEILING FLOOR HALF_UP HALF_DOWN HALF_EVEN UNNECESSARY 
5.5 6 5 6 5 6 5 6 抛出 ArithmeticException 
2.5 3 2 3 2 3 2 2 抛出 ArithmeticException 
1.6 2 1 2 1 2 2 2 抛出 ArithmeticException 
1.1 2 1 2 1 1 1 1 抛出 ArithmeticException 
1.0 1 1 1 1 1 1 1 1 -1.0 -1 -1 -1 -1 -1 -1 -1 -1 -1.1 -2 -1 -1 -2 -1 -1 -1 抛出 ArithmeticException 
-1.6 -2 -1 -1 -2 -2 -2 -2 抛出 ArithmeticException 
-2.5 -3 -2 -2 -3 -3 -2 -2 抛出 ArithmeticException 
-5.5 -6 -5 -5 -6 -6 -5 -6 抛出 ArithmeticException


5. MathContext 示例

//计算数的位数较小 , 最后结果都一样
BigDecimal b1 = new BigDecimal( "23.323" );
BigDecimal b2 = new BigDecimal( "323.57" );
//346.893 precision=6 , unscale=346893 , scale=3
info( b1.add(b2 ,  MathContext.DECIMAL32) );
//346.893 precision=6 , unscale=346893 , scale=3
info( b1.add(b2 ,  MathContext.DECIMAL64) );
//346.893 precision=6 , unscale=346893 , scale=3
info( b1.add(b2 ,  MathContext.DECIMAL128) );
 
//DECIMAL32-->precision最大为7
//DECIMAL64-->precision最大为16
//DECIMAL128-->precision最大为34
b1 = new BigDecimal( "1231243434341223.25532323" );
b2 = new BigDecimal( "4532323.55457" );
//1.231243E+15 precision=7 , unscale=1231243 , scale=-9
info( b1.add(b2 ,  MathContext.DECIMAL32) );
//1231243438873547 precision=16 , unscale=1231243438873547 , scale=0
info( b1.add(b2 ,  MathContext.DECIMAL64) );
//1231243438873546.80989323 precision=24 , unscale=123124343887354680989323 , scale=8
info( b1.add(b2 ,  MathContext.DECIMAL128) );


6. equals 和 sort

注:如果 BigDecimal 对象用作 SortedMap 中的键或 SortedSet 中的元素 , 则应特别小心 , 因为 BigDecimal 的自然排序与 equals 方法不一致。

Map接口是按照 equals 操作定义的 , 但有序映射SortedMap使用它的 compareTo(或 compare)方法对所有键进行比较

BigDecimal b1 = new BigDecimal("28.000");
BigDecimal b2 = new BigDecimal(28);
//28.000 precision=5 , unscale=28000 , scale=3
info( b1 );
//28 precision=2 , unscale=28 , scale=0
info( b2 );
//false
System.out.println( b1.equals(b2) );
System.out.println( "b1.hashCode=" + b1.hashCode() );
System.out.println( "b2.hashCode=" + b2.hashCode() );
//0
System.out.println( b1.compareTo(b2) );
 
//注:如果 BigDecimal 对象用作 SortedMap 中的键或 SortedSet 中的元素 , 则应特别小心 , 因为 BigDecimal 的自然排序与 equals 方法不一致。
Map<BigDecimal ,  String> treeMap = new TreeMap<BigDecimal , String>();
treeMap.put(b1 ,  "28.000");
treeMap.put(b2 ,  "28");
treeMap.put(new BigDecimal("12") ,  "12");
//{12=12 ,  28.000=28}
System.out.println( treeMap );
 
 
Map<BigDecimal ,  String> hashMap = new HashMap<BigDecimal ,  String>();
hashMap.put(b1 ,  "28.000");
hashMap.put(b2 ,  "28");
hashMap.put(new BigDecimal("12") ,  "12");
//{28.000=28.000 ,  12=12 ,  28=28}
System.out.println( hashMap );
 
// Map接口是按照 equals 操作定义的 , 但有序映射SortedMap使用它的 compareTo(或 compare)方法对所有键进行比较


7. 综合示例

    static void actionByDouble(){
        String[] arr = new String[]{"3649926.00" , "213582.00" , "253270.00" , 
                "172841.00" , "204571.00" , "177974.00" , "189629.00" , "155114.00" , 
                "135878.00" , "119562.00" , "132559.00" , "159562.00" , "161837.00" , 
                "103169.00" , "136250.00" , "132953.00" , "121470.00000000001"};
        BigDecimal total = BigDecimal.ZERO;
        for( String s : arr ){
            double d = Double.valueOf(s);
            BigDecimal num = new BigDecimal(d);
            total = total.add( num );
        }
        //actionByDouble: total=6220147.00
        System.out.println( "actionByDouble: total=" + total.setScale(2 ,  BigDecimal.ROUND_HALF_UP) );
    }


1. BigDecimalTest.java

public class BigDecimalTest {
 
	/**
	 * @param args
	 */
	public static void main(final String[] args) {
		actionByString();
		actionByDouble();
		test();
		matchContext();
		equalsAndSort();
	}
 
	static void test(){
		
		//正数的[精度]precision、[非标度值]unscale、[标度]scale
		//0 precision=1 , unscale=0 , scale=0
		BigDecimal tmp = new BigDecimal("0");
		System.out.println( "0 precision=" + tmp.precision() +" , unscale=" + tmp.unscaledValue()+ " , scale=" + tmp.scale() );
		
		tmp = new BigDecimal("0.0");
		//0.0 precision=1 , unscale=0 , scale=1
		System.out.println( "0.0 precision=" + tmp.precision() +" , unscale=" + tmp.unscaledValue()+ " , scale=" + tmp.scale());
		
		tmp = new BigDecimal("1");
		//1 precision=1 , unscale=1 , scale=0
		System.out.println( "1 precision=" + tmp.precision() +" , unscale=" + tmp.unscaledValue()+ " , scale=" + tmp.scale());
		
		tmp = new BigDecimal("1.0");
		//1.0 precision=2 , unscale=10 , scale=1
		System.out.println( "1.0 precision=" + tmp.precision() +" , unscale=" + tmp.unscaledValue()+ " , scale=" + tmp.scale());
		
		tmp = new BigDecimal("0.1");
		//0.1 precision=1 , unscale=1 , scale=1
		System.out.println( "0.1 precision=" + tmp.precision() +" , unscale=" + tmp.unscaledValue()+ " , scale=" + tmp.scale());
		
		tmp = new BigDecimal("122.000");
		//122.000 precision=6 , unscale=122000 , scale=3
		System.out.println( "122.000 precision=" + tmp.precision() +" , unscale=" + tmp.unscaledValue()+ " , scale=" + tmp.scale());
		
		
		//----------负数的[精度]precision、[非标度值]unscale、[标度]scale
		//-0 precision=1 , unscale=0 , scale=0
		tmp = new BigDecimal("-0");
		System.out.println( "-0 precision=" + tmp.precision() +" , unscale=" + tmp.unscaledValue()+ " , scale=" + tmp.scale() );
		
		tmp = new BigDecimal("-0.0");
		//-0.0 precision=1 , unscale=0 , scale=1
		System.out.println( "-0.0 precision=" + tmp.precision() +" , unscale=" + tmp.unscaledValue()+ " , scale=" + tmp.scale());
		
		tmp = new BigDecimal("-1");
		//-1 precision=1 , unscale=-1 , scale=0
		System.out.println( "-1 precision=" + tmp.precision() +" , unscale=" + tmp.unscaledValue()+ " , scale=" + tmp.scale());
		
		tmp = new BigDecimal("-1.0");
		//-1.0 precision=2 , unscale=-10 , scale=1
		System.out.println( "-1.0 precision=" + tmp.precision() +" , unscale=" + tmp.unscaledValue()+ " , scale=" + tmp.scale());
		
		tmp = new BigDecimal("-0.1");
		//-0.1 precision=1 , unscale=-1 , scale=1
		System.out.println( "-0.1 precision=" + tmp.precision() +" , unscale=" + tmp.unscaledValue()+ " , scale=" + tmp.scale());
		
		tmp = new BigDecimal("-122.000");
		//-122.000 precision=6 , unscale=-122000 , scale=3
		System.out.println( "-122.000 precision=" + tmp.precision() +" , unscale=" + tmp.unscaledValue()+ " , scale=" + tmp.scale());
		
		
		//强制设置[标度]scale
		//----scale默认的0设置为3
		BigDecimal de1 = new BigDecimal("125");
		System.out.println( "默认scale为0:" + de1 );
		System.out.println( "强制设置scale为3:" + de1.setScale(3) );
		
		//----scale由初始的2设置为5
		de1 = new BigDecimal("28.02");
		System.out.println( "初始scale为2:" + de1 );
		System.out.println( "强制设置scale为5:" + de1.setScale(5) );
		
		//----scale由初始的7设置为2
		de1 = new BigDecimal("177.1234567");
		System.out.println( "初始scale为7:" + de1 );
		try{
			//精度由大变小(7->2)必须设置舍入规则
			System.out.println( "强制设置scale为2:" + de1.setScale(2) );
		}catch(Exception e){
			System.out.println( e.getMessage() );
		}
		System.out.println( "强制设置scale为2:" + de1.setScale(2 ,  RoundingMode.HALF_UP) );
		
		BigDecimal b1 = new BigDecimal("1");
		BigDecimal b2 = new BigDecimal("2");
		BigDecimal b3 = new BigDecimal("3");
		//按指定精度 , 向上0.333∞ -> 1
		System.out.println("ROUND_CEILING:1/3 = " + b1.divide(b3 ,  RoundingMode.CEILING) );
		//按指定精度 , 向上0.333∞ -> 1
		System.out.println("ROUND_UP:1/3 = " + b1.divide(b3 ,  RoundingMode.UP) );
		
		//按指定精度 , 向下0.333∞ -> 0
		System.out.println("ROUND_DOWN:1/3 = " + b1.divide(b3 ,  RoundingMode.DOWN) );
		//按指定精度 , 向下0.333∞ -> 0
		System.out.println("ROUND_FLOOR:1/3 = " + b1.divide(b3 ,  RoundingMode.FLOOR) );
		
		//按指定精度 , 趋近最近的数 , 0.333∞ -> 0
		System.out.println("ROUND_HALF_DOWN:1/3 = " + b1.divide(b3 ,  RoundingMode.HALF_DOWN) );
		//按指定精度 , 趋近最近的数 , 0.333∞ -> 0
		System.out.println("ROUND_HALF_UP:1/3 = " + b1.divide(b3 ,  RoundingMode.HALF_UP) );
		
		//按指定精度 , 趋近最近的数 , 0.5向下 0.5-> 0
		System.out.println("ROUND_HALF_DOWN:1/2 = " + b1.divide(b2 ,  RoundingMode.HALF_DOWN) );
		//按指定精度 , 趋近最近的数 , 0.5向上 0.5-> 1
		System.out.println("ROUND_HALF_UP:1/2 = " + b1.divide(b2 ,  RoundingMode.HALF_UP) );
		
		//按指定精度 , 趋近最近的数 , 0.333∞ -> 1
		System.out.println("ROUND_HALF_DOWN:2/3 = " + b2.divide(b3 ,  RoundingMode.HALF_DOWN) );
		//按指定精度 , 趋近最近的数 , 0.333∞ -> 1
		System.out.println("ROUND_HALF_UP:2/3 = " + b2.divide(b3 ,  RoundingMode.HALF_UP) );
		
		
		//按指定精度 , 趋近最近的数 , 0.5 -> 偶数
		//ROUND_HALF_EVEN:1/3 = 0
		System.out.println("ROUND_HALF_EVEN:1/3 = " + b1.divide(b3 ,  RoundingMode.HALF_EVEN) );
		//ROUND_HALF_EVEN:1/2 = 0
		System.out.println("ROUND_HALF_EVEN:1/2 = " + b1.divide(b2 ,  RoundingMode.HALF_EVEN) );
		//ROUND_HALF_EVEN:2/3 = 1
		System.out.println("ROUND_HALF_EVEN:2/3 = " + b2.divide(b3 ,  RoundingMode.HALF_EVEN) );
		
		//明确知道结果 , 否则抛异常
		System.out.println("ROUND_UNNECESSARY:2 = " + b2.setScale(2 ,  RoundingMode.UNNECESSARY));
		try{
			//计算中的结果无法使用:ROUND_UNNECESSARY
			System.out.println("ROUND_UNNECESSARY:1/2 = " + b1.divide(b2 ,  RoundingMode.UNNECESSARY) );
		}catch( Exception e ){
			//Rounding necessary
			System.out.println( e.getMessage() );
		}
		
	}
	
	static void matchContext(){
		//计算数的位数较小 , 最后结果都一样
		BigDecimal b1 = new BigDecimal( "23.323" );
		BigDecimal b2 = new BigDecimal( "323.57" );
		//346.893 precision=6 , unscale=346893 , scale=3
		info( b1.add(b2 ,  MathContext.DECIMAL32) );
		//346.893 precision=6 , unscale=346893 , scale=3
		info( b1.add(b2 ,  MathContext.DECIMAL64) );
		//346.893 precision=6 , unscale=346893 , scale=3
		info( b1.add(b2 ,  MathContext.DECIMAL128) );
		
		//DECIMAL32-->precision最大为7
		//DECIMAL64-->precision最大为16
		//DECIMAL128-->precision最大为34
		b1 = new BigDecimal( "1231243434341223.25532323" );
		b2 = new BigDecimal( "4532323.55457" );
		//1.231243E+15 precision=7 , unscale=1231243 , scale=-9
		info( b1.add(b2 ,  MathContext.DECIMAL32) );
		//1231243438873547 precision=16 , unscale=1231243438873547 , scale=0
		info( b1.add(b2 ,  MathContext.DECIMAL64) );
		//1231243438873546.80989323 precision=24 , unscale=123124343887354680989323 , scale=8
		info( b1.add(b2 ,  MathContext.DECIMAL128) );
	}
	
	static void equalsAndSort(){
		BigDecimal b1 = new BigDecimal("28.000");
		BigDecimal b2 = new BigDecimal(28);
		//28.000 precision=5 , unscale=28000 , scale=3
		info( b1 );
		//28 precision=2 , unscale=28 , scale=0
		info( b2 );
		//false
		System.out.println( b1.equals(b2) );
		System.out.println( "b1.hashCode=" + b1.hashCode() );
		System.out.println( "b2.hashCode=" + b2.hashCode() );
		//0
		System.out.println( b1.compareTo(b2) );
		
		//注:如果 BigDecimal 对象用作 SortedMap 中的键或 SortedSet 中的元素 , 则应特别小心 , 因为 BigDecimal 的自然排序与 equals 方法不一致。
		Map<BigDecimal ,  String> treeMap = new TreeMap<BigDecimal , String>();
		treeMap.put(b1 ,  "28.000");
		treeMap.put(b2 ,  "28");
		treeMap.put(new BigDecimal("12") ,  "12");
		//{12=12 ,  28.000=28}
		System.out.println( treeMap );
		
		
		Map<BigDecimal ,  String> hashMap = new HashMap<BigDecimal ,  String>();
		hashMap.put(b1 ,  "28.000");
		hashMap.put(b2 ,  "28");
		hashMap.put(new BigDecimal("12") ,  "12");
		//{28.000=28.000 ,  12=12 ,  28=28}
		System.out.println( hashMap );
		
		// Map接口是按照 equals 操作定义的 , 但有序映射SortedMap使用它的 compareTo(或 compare)方法对所有键进行比较
	}
	
	static void actionByString(){
		String[] arr = new String[]{"3649926.00" , "213582.00" , "253270.00" , 
				"172841" , "204571" , "177974" , "189629" , "155114" , 
				"135878" , "119562" , "132559" , "159562" , "161837" , 
				"103169" , "136250" , "132953" , "121470.00000434"};
		BigDecimal total = BigDecimal.ZERO;
		for( String s : arr ){
			BigDecimal num = new BigDecimal(s);
			total = total.add( num );
		}
		//actionByString: total=6220147.00
		System.out.println( "actionByString: total=" + total.setScale(2 ,  RoundingMode.HALF_UP) );
		
		
	}
	
	static void actionByDouble(){
		String[] arr = new String[]{"3649926.00" , "213582.00" , "253270.00" , 
				"172841.00" , "204571.00" , "177974.00" , "189629.00" , "155114.00" , 
				"135878.00" , "119562.00" , "132559.00" , "159562.00" , "161837.00" , 
				"103169.00" , "136250.00" , "132953.00" , "121470.00000000001"};
		BigDecimal total = BigDecimal.ZERO;
		for( String s : arr ){
			double d = Double.valueOf(s);
			BigDecimal num = new BigDecimal(d);
			total = total.add( num );
		}
		//actionByDouble: total=6220147.00
		System.out.println( "actionByDouble: total=" + total.setScale(2 ,  BigDecimal.ROUND_HALF_UP) );
	}
	
	/**
	 * 指定BigDecimal的内部信息
	 * @param decimal
	 */
	static void info( final BigDecimal decimal ){
		System.out.println( decimal + " precision=" + decimal.precision() +" , unscale=" + decimal.unscaledValue()+ " , scale=" + decimal.scale());
	}
	
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值