1 ackage com.vstsoft.common.util;2
3 import java.math.BigDecimal;4 import java.text.DecimalFormat;5
6 import org.slf4j.Logger;7 import org.slf4j.LoggerFactory;8
9 /**10 * @Comments : 由于Java的简单类型不能够精确的对浮点数进行运算, 这个工具类提供精确的浮点数运算,包括加减乘除和四舍五入。11 */
12 public class ArithUtil {13 //默认除法运算精度
14 private static final int DEFAULT_DIV_SCALE = 10;15 private final static Logger logger =LoggerFactory.getLogger(ArithUtil.class);16
17 /**18 * 提供精确的加法运算。19 *20 * @param v121 * @param v222 * @return 两个参数的和23 */
24 public static BigDecimal add(BigDecimal b1, BigDecimal b2) {25 returnb1.add(b2);26 }27
28 public static BigDecimal add(double v1, doublev2) {29 BigDecimal b1 = newBigDecimal(Double.toString(v1));30 BigDecimal b2 = newBigDecimal(Double.toString(v2));31 returnadd(b1, b2);32 }33
34 /**35 * 提供精确的减法运算。36 *37 * @param v138 * @param v239 * @return 两个参数的差40 */
41
42 public static BigDecimal subtract(BigDecimal b1, BigDecimal b2) {43 returnb1.subtract(b2);44 }45
46 public static BigDecimal subtract(double v1, doublev2) {47 BigDecimal b1 = newBigDecimal(Double.toString(v1));48 BigDecimal b2 = newBigDecimal(Double.toString(v2));49 returnb1.subtract(b2);50 }51
52 /**53 * 提供精确的乘法运算。54 *55 * @param v156 * @param v257 * @return 两个参数的积58 */
59
60 public static BigDecimal multiply(BigDecimal b1, BigDecimal b2) {61 returnb1.multiply(b2);62 }63
64 public static BigDecimal multiply(double v1, doublev2) {65 BigDecimal b1 = newBigDecimal(Double.toString(v1));66 BigDecimal b2 = newBigDecimal(Double.toString(v2));67 returnb1.multiply(b2);68 }69
70 /**71 * 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到 小数点以后10位,以后的数字四舍五入,舍入模式采用ROUND_HALF_EVEN72 *73 * @param v174 * 被除数75 * @param v276 * 除数77 * @return 两个参数的商78 */
79
80 public static BigDecimal divide(BigDecimal b1, BigDecimal b2) {81 returndivide(b1, b2, DEFAULT_DIV_SCALE);82 }83
84 public static BigDecimal divide(double v1, doublev2) {85 returndivide(v1, v2, DEFAULT_DIV_SCALE);86 }87
88 /**89 * 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指 定精度,以后的数字四舍五入。舍入模式采用ROUND_HALF_EVEN90 *91 * @param v192 * 被除数93 * @param v294 * 除数95 * @param scale96 * 表示需要精确到小数点以后几位。97 * @return 两个参数的商98 */
99
100 public static BigDecimal divide(BigDecimal b1, BigDecimal b2, intscale) {101 returndivide(b1, b2, scale, BigDecimal.ROUND_HALF_EVEN);102 }103
104 public static BigDecimal divide(double v1, double v2, intscale) {105 returndivide(v1, v2, scale, BigDecimal.ROUND_HALF_EVEN);106 }107
108 /**109 * 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指 定精度,以后的数字四舍五入。舍入模式采用用户指定舍入模式110 *111 * @param v1112 * 被除数113 * @param v2114 * 除数115 * @param scale116 * 表示需要精确到小数点以后几位117 * @param round_mode118 * 表示用户指定的舍入模式119 * @return 两个参数的商120 */
121
122 public static BigDecimal divide(BigDecimal b1, BigDecimal b2, int scale, intround_mode) {123 if (scale < 0) {124 throw new IllegalArgumentException("The scale must be a positive integer or zero");125 }126 returnb1.divide(b2, scale, round_mode);127 }128
129 public static BigDecimal divide(double v1, double v2, int scale, intround_mode) {130 if (scale < 0) {131 throw new IllegalArgumentException("The scale must be a positive integer or zero");132 }133 BigDecimal b1 = newBigDecimal(Double.toString(v1));134 BigDecimal b2 = newBigDecimal(Double.toString(v2));135 returnb1.divide(b2, scale, round_mode);136 }137
138 /**139 * 提供保留两位小数的四舍五入处理,舍入模式采用ROUND_HALF_EVEN140 *141 * @param v142 * 需要四舍五入的数字143 * @param scale144 * 小数点后保留几位145 * @return 四舍五入后的结果146 */
147
148 public static BigDecimal round(BigDecimal b) {149 return round(b, 2);150 }151
152 /**153 * 提供精确的小数位四舍五入处理,舍入模式采用ROUND_HALF_EVEN154 *155 * @param v156 * 需要四舍五入的数字157 * @param scale158 * 小数点后保留几位159 * @return 四舍五入后的结果160 */
161
162 public static BigDecimal round(BigDecimal b, intscale) {163 returnround(b, scale, BigDecimal.ROUND_HALF_EVEN);164 }165
166 /**167 * 提供精确的小数位四舍五入处理168 *169 * @param v170 * 需要四舍五入的数字171 * @param scale172 * 小数点后保留几位173 * @param round_mode174 * 指定的舍入模式175 * @return 四舍五入后的结果176 */
177
178 public static BigDecimal round(BigDecimal b, int scale, intround_mode) {179 if (scale < 0) {180 logger.error(StaticUtil.UTILERROR, "scale:" + scale + ",the scale must be a positive integer or zero");181 throw new IllegalArgumentException("The scale must be a positive integer or zero");182 }183 returnb.setScale(scale, round_mode);184 }185
186 public static voidmain(String[] args) {187 BigDecimal b1 = new BigDecimal("100");188 BigDecimal b2 = new BigDecimal("1.765");189 BigDecimal b3 = new BigDecimal("1.65");190 BigDecimal b4 = new BigDecimal("7");191
192 //精确除法运算
193 logger.info(divide(b1, b4).toString());194 logger.info(divide(b1, b4, 1).toString());195
196 logger.info(round(b2, 2, BigDecimal.ROUND_HALF_EVEN).toString());197 logger.info(round(b2, 2, BigDecimal.ROUND_HALF_UP).toString());198 logger.info(round(b2, 2, BigDecimal.ROUND_HALF_DOWN).toString());199
200 logger.info(round(b3, 1, BigDecimal.ROUND_HALF_EVEN).toString());201 logger.info(round(b3, 1, BigDecimal.ROUND_HALF_UP).toString());202 logger.info(round(b3, 1, BigDecimal.ROUND_HALF_DOWN).toString());203
204 //数学运算在实际中存在的问题
205 /**206 * 0.060000000000000005 0.5800000000000001 401.49999999999994207 * 1.2329999999999999208 */
209 logger.info("错误的结果:");210 logger.info(0.05 + 0.01 + "");211 logger.info(1.0 - 0.42 + "");212 logger.info(4.015 * 100 + "");213 logger.info(123.3 / 100 + "");214 logger.info("精确计算的结果:");215 logger.info(ArithUtil.add(new BigDecimal("0.056789123446"), new BigDecimal("0.01234566789")).toString());216 logger.info(ArithUtil.subtract(new BigDecimal("1.012345678912"), new BigDecimal("0.42345689127")).toString());217 logger.info(ArithUtil.multiply(new BigDecimal("4.0156789"), new BigDecimal("100.12345")).toString());218 logger.info(ArithUtil.divide(new BigDecimal("123.3"), new BigDecimal("100")).toString());219 /**220 * 输入结果为 504.549999999999982946974341757595539093017578125 实际结果应为 504.55221 */
222 logger.info("BigDecimal 的不精确计算问题:");223 BigDecimal bg1 = new BigDecimal(100.91);224 BigDecimal bg2 = new BigDecimal(5);225 BigDecimal bg3 =bg1.multiply(bg2);226 logger.info(bg3 + "");227 DecimalFormat df = new DecimalFormat("¥0,000.00");228 logger.info("精确计算的结果:");229
230 BigDecimal bg4 = multiply(new BigDecimal("1000000000.91"), new BigDecimal("5"));231 logger.info(ArithUtil.round(bg4).toString());232 BigDecimal bg5 = multiply(new BigDecimal("10000000"), new BigDecimal("9999999"));233 logger.info(ArithUtil.round(bg5).toString());234 logger.info("***************************************************");235
236 }237 }