项目中遇到了数值运算,如网上所写的,一般有这几个方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | /** * 提供精确的加法运算。 * @param v1 被加数 * @param v2 加数 * @return 两个参数的和 */ public static double add( double v1, double v2) { BigDecimal b1 = new BigDecimal(Double.toString(v1)); BigDecimal b2 = new BigDecimal(Double.toString(v2)); return (b1.add(b2)).doubleValue(); } /** * 提供精确的减法运算。 * @param v1 被减数 * @param v2 减数 * @return 两个参数的差 */ public static double sub( double v1, double v2) { BigDecimal b1 = new BigDecimal(Double.toString(v1)); BigDecimal b2 = new BigDecimal(Double.toString(v2)); return (b1.subtract(b2)).doubleValue(); } /** * 提供精确的乘法运算。 * @param v1 被乘数 * @param v2 乘数 * @return 两个参数的积 */ public static double mul( double v1, double v2) { BigDecimal b1 = new BigDecimal(Double.toString(v1)); BigDecimal b2 = new BigDecimal(Double.toString(v2)); return (b1.multiply(b2)).doubleValue(); } /** * 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指 * 定精度,以后的数字四舍五入。 * @param v1 被除数 * @param v2 除数 * @param scale 表示需要精确到小数点以后几位。 * @return 两个参数的商 */ public static double div( double v1, double v2, int scale) { if (scale < 0 ) { System.err.println( "除法精度必须大于0!" ); return 0 ; } BigDecimal b1 = new BigDecimal(Double.toString(v1)); BigDecimal b2 = new BigDecimal(Double.toString(v2)); return (b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP)).doubleValue(); } |
但是这里,我还有两个地方需要做一些变化:
1、乘法运算需要做精度的四舍五入
2、double会自动进行科学计数法
对于第一点新增mul方法
1 2 3 4 5 | public static double mul( double v1, double v2, int scale) { BigDecimal b1 = new BigDecimal(Double.toString(v1)); BigDecimal b2 = new BigDecimal(Double.toString(v2)); return (b1.multiply(b2).setScale(scale, RoundingMode.HALF_UP)).doubleValue(); } |
这样就可以对所做的运算进行需要的精度的四舍五入
第二点新增double2Str方法
1 2 3 4 | private static String double2Str( double number) { return DecimalFormat.getInstance().format(number).replace( "," , "" ); } |
不需要进行格式化,因为项目中把科学计数法的数字传给客户端.Net接收,无法正确转换成数值(除非客户端特殊处理这个科学计数法数值)
当时,对第一点做了一个错误的精度处理:MathContext
1 2 3 4 | public static double mul( double v1, double v2, int scale) { BigDecimal b1 = new BigDecimal(Double.toString(v1)); BigDecimal b2 = new BigDecimal(Double.toString(v2)); |
return b1.multiply(b2, new MathContext(scale,RoundingMode.HALF_UP)).doubleValue();
1 2 | } |
这个MathContext是从左边第一个数开始算起,而不是从小数点后开始算
补充一下舍入RoundingMode
在RoundingMode中HALF_DOWN 没有按照我预期的对数值进行向下取数值有点疑惑
1 2 | double d3 = 102207767.555 ; d3= new BigDecimal(d3).setScale( 2 ,RoundingMode.HALF_DOWN).doubleValue(); |
打印后d3显示102207767.56 不应该是102207767.55?
1 | |
ROUND_CEILING
Rounding mode to round towards positive infinity.
向正无穷方向舍入
ROUND_DOWN
Rounding mode to round towards zero.
向零方向舍入
ROUND_FLOOR
Rounding mode to round towards negative infinity.
向负无穷方向舍入
ROUND_HALF_DOWN
Rounding mode to round towards "nearest neighbor" unless both neighbors are equidistant, in which case round down.
向(距离)最近的一边舍入,除非两边(的距离)是相等,如果是这样,向下舍入, 例如1.55 保留一位小数结果为1.5
ROUND_HALF_EVEN
Rounding mode to round towards the "nearest neighbor" unless both neighbors are equidistant, in which case, round towards the even neighbor.
向(距离)最近的一边舍入,除非两边(的距离)是相等,如果是这样,如果保留位数是奇数,使用ROUND_HALF_UP ,如果是偶数,使用ROUND_HALF_DOWN
ROUND_HALF_UP
Rounding mode to round towards "nearest neighbor" unless both neighbors are equidistant, in which case round up.
向(距离)最近的一边舍入,除非两边(的距离)是相等,如果是这样,向上舍入, 1.55保留一位小数结果为1.6
ROUND_UNNECESSARY
Rounding mode to assert that the requested operation has an exact result, hence no rounding is necessary.
计算结果是精确的,不需要舍入模式
ROUND_UP
Rounding mode to round away from zero.
向远离0的方向舍入