首页

BigDecimal通过setScale设置小数位数发生ArithmeticException

标签:java,BigDecimal,setScale,小数,ArithmeticException,Rounding necessary     发布时间:2015-08-30   

一、前言

通常进行数值计算时,我们会先将double或float等转为BigDecimal再处理,然后对计算结果通过setScale方法取指定的小数位;但是在这里有时会遇到java.lang.ArithmeticException: Rounding necessary,下面我们会对此问题进行演示和说明。

二、代码示例

1. 这里以double转BigDecimal后获取不同小数位值来举例说明,具体如下:

public static void main(String[] args) {@b@      double d = 10.0000000001;@b@      String s = "10.0000000001";@b@      BigDecimal newBigDecimal = new BigDecimal(d);@b@      BigDecimal newStringBigDecimal = new BigDecimal(s);@b@      BigDecimal valueOfBigDecimal = BigDecimal.valueOf(d);@b@      // newBigDecimal===================================@b@      System.out.println("newBigDecimal's scale:" + newBigDecimal.scale());@b@      try {@b@         System.out.println("newBigDecimal setScale(50):" + newBigDecimal.setScale(50));@b@      } catch (Exception e) {@b@         System.out.println("newBigDecimal setScale(50):" + e);@b@      }@b@      try {@b@         System.out.println("newBigDecimal setScale(49):" + newBigDecimal.setScale(49));@b@      } catch (Exception e) {@b@         System.out.println("newBigDecimal setScale(49):" + e);@b@      }@b@      try {@b@         System.out.println("newBigDecimal setScale(48):" + newBigDecimal.setScale(48));@b@      } catch (Exception e) {@b@         System.out.println("newBigDecimal setScale(48):" + e);@b@         System.out.println("newBigDecimal setScale(48, RoundingMode.HALF_UP):" + newBigDecimal.setScale(48, RoundingMode.HALF_UP));@b@      }@b@      @b@      // valueOfBigDecimal======================================@b@      System.out.println("valueOfBigDecimal's scale:" + valueOfBigDecimal.scale());@b@      try {@b@         System.out.println("valueOfBigDecimal setScale(50):" + valueOfBigDecimal.setScale(50));@b@      } catch (Exception e) {@b@         System.out.println("valueOfBigDecimal setScale(50):" + e);@b@      }@b@      try {@b@         System.out.println("valueOfBigDecimal setScale(49):" + valueOfBigDecimal.setScale(49));@b@      } catch (Exception e) {@b@         System.out.println("valueOfBigDecimal setScale(49):" + e);@b@      }@b@      try {@b@         System.out.println("valueOfBigDecimal setScale(48):" + valueOfBigDecimal.setScale(48));@b@      } catch (Exception e) {@b@         System.out.println("valueOfBigDecimal setScale(48):" + e);@b@         System.out.println("valueOfBigDecimal setScale(48, RoundingMode.HALF_UP):" + valueOfBigDecimal.setScale(48, RoundingMode.HALF_UP));@b@      }@b@      // newStringBigDecimal======================================@b@      System.out.println("newStringBigDecimal's scale:" + newStringBigDecimal.scale());@b@      try {@b@         System.out.println("newStringBigDecimal setScale(50):" + newStringBigDecimal.setScale(50));@b@      } catch (Exception e) {@b@         System.out.println("newStringBigDecimal setScale(50):" + e);@b@      }@b@      try {@b@         System.out.println("newStringBigDecimal setScale(49):" + newStringBigDecimal.setScale(49));@b@      } catch (Exception e) {@b@         System.out.println("newStringBigDecimal setScale(49):" + e);@b@      }@b@      try {@b@         System.out.println("newStringBigDecimal setScale(48):" + newStringBigDecimal.setScale(48));@b@      } catch (Exception e) {@b@         System.out.println("newStringBigDecimal setScale(48):" + e);@b@         System.out.println("newStringBigDecimal setScale(48, RoundingMode.HALF_UP):" + newStringBigDecimal.setScale(48, RoundingMode.HALF_UP));@b@      }@b@      @b@      d = 10.01;@b@      s = "10.01";@b@      newBigDecimal = new BigDecimal(d);@b@      valueOfBigDecimal = BigDecimal.valueOf(d);@b@      newStringBigDecimal = new BigDecimal(s);@b@      // newBigDecimal==========================================@b@      System.out.println("newBigDecimal's scale:" + newBigDecimal.scale());@b@      try {@b@         System.out.println("newBigDecimal setScale(3):" + newBigDecimal.setScale(3));@b@      } catch (Exception e) {@b@         System.out.println("newBigDecimal setScale(3):" + e);@b@         System.out.println("newBigDecimal setScale(3, RoundingMode.HALF_UP):" + newBigDecimal.setScale(3, RoundingMode.HALF_UP));@b@      }@b@      try {@b@         System.out.println("newBigDecimal setScale(2):" + newBigDecimal.setScale(2));@b@      } catch (Exception e) {@b@         System.out.println("newBigDecimal setScale(2):" + e);@b@         System.out.println("newBigDecimal setScale(2, RoundingMode.HALF_UP):" + newBigDecimal.setScale(2, RoundingMode.HALF_UP));@b@      }@b@      try {@b@         System.out.println("newBigDecimal setScale(1):" + newBigDecimal.setScale(1));@b@      } catch (Exception e) {@b@         System.out.println("newBigDecimal setScale(1):" + e);@b@         System.out.println("newBigDecimal setScale(1, RoundingMode.HALF_UP):" + newBigDecimal.setScale(1, RoundingMode.HALF_UP));@b@      }@b@      @b@      // valueOfBigDecimal======================================@b@      System.out.println("valueOfBigDecimal's scale:" + valueOfBigDecimal.scale());@b@      try {@b@         System.out.println("valueOfBigDecimal setScale(3):" + valueOfBigDecimal.setScale(3));@b@      } catch (Exception e) {@b@         System.out.println("valueOfBigDecimal setScale(3):" + e);@b@      }@b@      try {@b@         System.out.println("valueOfBigDecimal setScale(2):" + valueOfBigDecimal.setScale(2));@b@      } catch (Exception e) {@b@         System.out.println("valueOfBigDecimal setScale(2):" + e);@b@      }@b@      try {@b@         System.out.println("valueOfBigDecimal setScale(1):" + valueOfBigDecimal.setScale(1));@b@      } catch (Exception e) {@b@         System.out.println("valueOfBigDecimal setScale(1):" + e);@b@         System.out.println("valueOfBigDecimal setScale(1, RoundingMode.HALF_UP):" + valueOfBigDecimal.setScale(1, RoundingMode.HALF_UP));@b@      }@b@      // @b@      // newStringBigDecimal======================================@b@      System.out.println("newStringBigDecimal's scale:" + newStringBigDecimal.scale());@b@      try {@b@         System.out.println("newStringBigDecimal setScale(3):" + newStringBigDecimal.setScale(3));@b@      } catch (Exception e) {@b@         System.out.println("newStringBigDecimal setScale(3):" + e);@b@      }@b@      try {@b@         System.out.println("newStringBigDecimal setScale(2):" + newStringBigDecimal.setScale(2));@b@      } catch (Exception e) {@b@         System.out.println("newStringBigDecimal setScale(2):" + e);@b@      }@b@      try {@b@         System.out.println("newStringBigDecimal setScale(1):" + newStringBigDecimal.setScale(1));@b@      } catch (Exception e) {@b@         System.out.println("newStringBigDecimal setScale(1):" + e);@b@         System.out.println("newStringBigDecimal setScale(1, RoundingMode.HALF_UP):" + newStringBigDecimal.setScale(1, RoundingMode.HALF_UP));@b@      }@b@   }

运算结果如下:

newBigDecimal's scale:49@b@newBigDecimal setScale(50):10.00000000010000000827403709990903735160827636718750@b@newBigDecimal setScale(49):10.0000000001000000082740370999090373516082763671875@b@newBigDecimal setScale(48):java.lang.ArithmeticException: Rounding necessary@b@newBigDecimal setScale(48, RoundingMode.HALF_UP):10.000000000100000008274037099909037351608276367188@b@valueOfBigDecimal's scale:10@b@valueOfBigDecimal setScale(50):10.00000000010000000000000000000000000000000000000000@b@valueOfBigDecimal setScale(49):10.0000000001000000000000000000000000000000000000000@b@valueOfBigDecimal setScale(48):10.000000000100000000000000000000000000000000000000@b@newStringBigDecimal's scale:10@b@newStringBigDecimal setScale(50):10.00000000010000000000000000000000000000000000000000@b@newStringBigDecimal setScale(49):10.0000000001000000000000000000000000000000000000000@b@newStringBigDecimal setScale(48):10.000000000100000000000000000000000000000000000000@b@newBigDecimal's scale:49@b@newBigDecimal's value:10.0099999999999997868371792719699442386627197265625@b@newBigDecimal setScale(3):java.lang.ArithmeticException: Rounding necessary@b@newBigDecimal setScale(3, RoundingMode.HALF_UP):10.010@b@newBigDecimal setScale(2):java.lang.ArithmeticException: Rounding necessary@b@newBigDecimal setScale(2, RoundingMode.HALF_UP):10.01@b@newBigDecimal setScale(1):java.lang.ArithmeticException: Rounding necessary@b@newBigDecimal setScale(1, RoundingMode.HALF_UP):10.0@b@valueOfBigDecimal's scale:2@b@valueOfBigDecimal setScale(3):10.010@b@valueOfBigDecimal setScale(2):10.01@b@valueOfBigDecimal setScale(1):java.lang.ArithmeticException: Rounding necessary@b@valueOfBigDecimal setScale(1, RoundingMode.HALF_UP):10.0@b@newStringBigDecimal's scale:2@b@newStringBigDecimal setScale(3):10.010@b@newStringBigDecimal setScale(2):10.01@b@newStringBigDecimal setScale(1):java.lang.ArithmeticException: Rounding necessary@b@newStringBigDecimal setScale(1, RoundingMode.HALF_UP):10.0

2. 结果分析:

通过运行结果我们会发现两种情况:

①通过new直接将double作为参数传入得到的值输出后并不等于原double值,传入string或valueOf方法得到的结果等于原值;事实上查看Java文档会发现有三种方式将double转为BigDecimal:1. new BigDecimal(double d); 2. new BigDecimal(String s);3.BigDecimal.valueOf(double d) ; 第一种是double的二进制形式的结果,所以BigDecimal的值并不一定为其原值,如上代码所示:10.0000000001转换后为10.0000000001000000082740370999090373516082763671875 ,共有49位小数(不同机器结果会不同),10.01转换后为10.0099999999999997868371792719699442386627197265625,第二种和第三种结果相同,仍然为原值,因为第三种相当于先将double转为String(Double.toString(double))。

②同时我们会发现,设置结果小数位数小于当前位数时,如果未设置进位方式会抛出异常:java.lang.ArithmeticException: Rounding necessary,提示我们进位方式必须,当我们设置四舍五入后即可,其他方式可查看RoundingMode枚举类。

三、结论:

通过上述分析,我们可以看出当对BigDecimal的值进位时需指定进位方式,否则会发生java.lang.ArithmeticException: Rounding necessary。

  • ◆ 相关内容