摘要:使用,保證精度的同時,能精準的進行四舍六入計算。類精確的數學運算使用來實現精準度因為精度的原因構造方法的結果有一定的不可預知性,例如因此建議使用。算法規則四舍六入五考慮,五后非零就進一,五后皆零看奇偶,五前為偶應舍去,五前為奇要進一。
四舍六入計算
算法規則: 四舍六入五考慮, 五后非零就進一, 五后皆零看奇偶, 五前為偶應舍去, 五前為奇要進一。
使用BigDecimal,保證精度的同時,能精準的進行四舍六入計算。
優化排列組合算法關于排列組合公式,請百度。網上一大堆算法,都先計算階乘再相除。但實際上應該先約分,一下子就節約了很多計算步驟。以排列公式來說P(n,r)=n!/(n-r)!,實際計算中就是n 乘到 n-r就可以了。組合公式就是排列算法再除以r的階乘。
MathUtil類import org.apache.commons.lang3.ArrayUtils; import java.math.BigDecimal; import java.math.RoundingMode; /** * 精確的數學運算 *測試用例使用 {@link java.math.BigDecimal}來實現精準度
* 因為精度的原因BigDecimal(double val)構造方法的結果有一定的不可預知性,例如: ** System.out.println(new BigDecimal(0.2)); //0.200000000000000011102230246251565404236316680908203125 * System.out.println(BigDecimal.valueOf(0.2f)); //0.20000000298023224 * System.out.println(BigDecimal.valueOf(0.2d)); //0.2 * System.out.println(BigDecimal.valueOf(0.2)); //0.2 * System.out.println(new BigDecimal("0.2")); //0.2 **因此建議使用new BigDecimal(String)。 * @author BBF */ public final class MathUtil { /** * PI,比Math.PI多兩位 */ public static final double PI = 3.1415926535897932384626; /** * 默認除法運算精度 */ private static final int DEFAULT_SCALE = 10; private static final double NUM_ROUND = 0.5; /** * 運算枚舉 */ private enum MathType { /** * 加法 */ ADD, /** * 減法 */ SUB, /** * 乘法 */ MULTI, /** * 除法 */ DIV } private MathUtil() { } /** * 轉換為{@link java.math.BigDecimal} *
為保證精度,先轉成{@link java.lang.String}然后再用構造函數
* @param value 數值 * @return {@link java.math.BigDecimal} */ private static BigDecimal convertToBigDecimal(Number value) { return value == null ? BigDecimal.ZERO : new BigDecimal(value.toString()); } /** * 提供精確的加法、減法和乘法運算 * @param type 運算法則 * @param scale 精確到小數點后幾位,只在除法有效 * @param values 多個值 * @return 四則運算結果 */ private static BigDecimal calculate(MathType type, int scale, Number[] values) { if (ArrayUtils.isEmpty(values)) { return BigDecimal.ZERO; } // 第一個數作為被加數、被減數或被乘數 Number value = values[0]; BigDecimal result = convertToBigDecimal(value); for (int i = 1, l = values.length; i < l; i++) { value = values[i]; if (value != null) { switch (type) { case ADD: result = result.add(convertToBigDecimal(value)); break; case SUB: result = result.subtract(convertToBigDecimal(value)); break; case MULTI: result = result.multiply(convertToBigDecimal(value)); break; case DIV: result = result.divide(convertToBigDecimal(value), scale, RoundingMode.HALF_UP); break; default: break; } } } return result; } /** * 提供精確的冪運算 * @param value 底數 * @param n 指數 * @return 冪的積 */ public static BigDecimal pow(Number value, int n) { return convertToBigDecimal(value).pow(n); } /** * 提供精確的加法運算 * @param values 多個值的字符串 * @return 和 */ public static BigDecimal add(Number... values) { return calculate(MathType.ADD, DEFAULT_SCALE, values); } /** * 提供精確的減法運算 * @param values 多個值的字符串 * @return 差 */ public static BigDecimal sub(Number... values) { return calculate(MathType.SUB, DEFAULT_SCALE, values); } /** * 提供精確的乘法運算 * @param values 多個值的字符串 * @return 積 */ public static BigDecimal multi(Number... values) { return calculate(MathType.MULTI, DEFAULT_SCALE, values); } /** * 提供(相對)精確的除法運算 *當發生除不盡的情況時,精確到小數點以后10位,以后的數字四舍五入
* @param values 多個值的字符串 * @return 商 */ public static BigDecimal div(Number... values) { return calculate(MathType.DIV, DEFAULT_SCALE, values); } /** * 提供(相對)精確的除法運算 *當發生除不盡的情況時,由scale參數指定精度,以后的數字四舍五入
* @param scale 精確到小數點后幾位,只在除法有效 * @param values 多個值的字符串 * @return 商 */ public static BigDecimal divByScale(int scale, Number... values) { if (scale < 0) { throw new IllegalArgumentException("The scale must be a positive integer or zero"); } return calculate(MathType.DIV, scale, values); } /** * 四舍六入五成雙算法 *四舍六入五成雙是一種比較精確比較科學的計數保留法,是一種數字修約規則。
** 算法規則: * 四舍六入五考慮, * 五后非零就進一, * 五后皆零看奇偶, * 五前為偶應舍去, * 五前為奇要進一。 ** @param value 需要科學計算的數據 * @param digit 保留的小數位 * @return 指定小數位數的數字 */ public static BigDecimal round(Number value, int digit) { // 小數進位,然后取整計算,再退位得到結果 BigDecimal ratio = pow(10, digit); // 進位后的數字 BigDecimal number = multi(value, ratio); // 獲取BigDecimal整數部分,直接舍棄小數部分 long integer = number.setScale(0, RoundingMode.DOWN).longValue(); // 獲取小數部分 double decimal = sub(number, integer).doubleValue(); if (decimal > NUM_ROUND) { // 四舍六入 integer = integer + 1; } if (decimal == NUM_ROUND && integer % 2 != 0) { // 五前為奇要進一 integer = integer + 1; } return div(integer, ratio).setScale(digit, RoundingMode.HALF_UP); } /** * 計算階乘 *n! = n * (n-1) * ... * end
* @param n 階乘起始 * @param end 階乘結束 * @return 結果 */ public static BigDecimal factorial(Number n, int end) { int st = n.intValue(); if (st < end) { return BigDecimal.ZERO; } if (st == end) { return BigDecimal.ONE; } return multi(n, factorial(sub(n, 1), end)); } /** * 計算階乘 *n! = n * (n-1) * ... * 2 * 1
* @param n 階乘起始 * @return 結果 */ public static BigDecimal factorial(Number n) { return factorial(n, 1); } /** * 計算排列 *P(n, r) = n!/(n-r)!
*從n個不同的元素中,取r個不重復的元素,按次序排列
* @param n 總數 * @param r 要取出數量 * @return 排列數 */ public static long arrangement(int n, int r) { if (n < r) { return 0; } // 對公式約分,實際上是計算了n 到 n-r的階乘 return factorial(n, n - r).longValue(); } /** * 計算組合 *C(n, r) = n!/((n-r)! * r!)
*從n個不同的元素中,取r個不重復的元素,不考慮順序
* @param n 總數 * @param r 要取出數量 * @return 組合數 */ public static long combination(int n, int r) { if (n < r) { return 0; } // 組合就是排列的結果再除以r的階乘 return div(arrangement(n, r), factorial(r)).longValue(); } }
import org.junit.Test; import java.math.BigDecimal; /** * MathUtil測試類 * @author BBF */ public class MathUtilTest { @Test public void showBigDecimal() { System.out.println(new BigDecimal(0.2)); //0.200000000000000011102230246251565404236316680908203125 System.out.println(BigDecimal.valueOf(0.2f)); //0.20000000298023224 System.out.println(BigDecimal.valueOf(0.2d)); //0.2 System.out.println(BigDecimal.valueOf(0.2)); //0.2 System.out.println(new BigDecimal("0.2")); //0.2 } @Test public void add() { BigDecimal bigDecimal = new BigDecimal("1.91"); double ab = MathUtil.add(8, 0.1, 0.2f, 0.3d, bigDecimal).doubleValue(); System.out.println("各種類型數值相加,預期:10.51 實際:" + ab); } @Test public void round() { System.out.println("四舍六入預期:4.24 實際:" + MathUtil.round(4.245, 2).toString()); System.out.println("四舍六入預期:4.24 實際:" + MathUtil.round(4.2450, 2).toString()); System.out.println("四舍六入預期:4.25 實際:" + MathUtil.round(4.2451, 2).toString()); System.out.println("四舍六入預期:4.22 實際:" + MathUtil.round(4.2250, 2).toString()); System.out.println("四舍六入預期:1.20 實際:" + MathUtil.round(1.2050, 2).toString()); System.out.println("四舍六入預期:1.22 實際:" + MathUtil.round(1.2150, 2).toString()); System.out.println("四舍六入預期:1.22 實際:" + MathUtil.round(1.2250, 2).toString()); System.out.println("四舍六入預期:1.24 實際:" + MathUtil.round(1.2350, 2).toString()); System.out.println("四舍六入預期:1.24 實際:" + MathUtil.round(1.2450, 2).toString()); System.out.println("四舍六入預期:1.26 實際:" + MathUtil.round(1.2550, 2).toString()); System.out.println("四舍六入預期:1.26 實際:" + MathUtil.round(1.2650, 2).toString()); System.out.println("四舍六入預期:1.28 實際:" + MathUtil.round(1.2750, 2).toString()); System.out.println("四舍六入預期:1.28 實際:" + MathUtil.round(1.2850, 2).toString()); System.out.println("四舍六入預期:1.30 實際:" + MathUtil.round(1.2950, 2).toString()); } @Test public void factorial() { System.out.println("階乘10!:預期:3628800 實際:" + MathUtil.factorial(10).toString()); } @Test public void arrangement() { System.out.println("排列P(10,2),預期:90 實際:" + MathUtil.arrangement(10, 2)); } @Test public void combination() { System.out.println("排列C(10,2),預期:45 實際:" + MathUtil.combination(10, 2)); } }
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/69515.html
摘要:浮點數類型包括單精度浮點數和雙精度浮點數。小結通過浮點數精度的問題,了解到浮點數的小數用二進制的表示。以后,在使用浮點數運算的時候,一定要慎之又慎,細節決定成敗。 概述 記錄下,工作中遇到的坑 ... 關于 PHP 浮點數運算,特別是金融行業、電子商務訂單管理、數據報表等相關業務,利用浮點數進行加減乘除時,稍不留神運算結果就會出現偏差,輕則損失幾十萬,重則會有信譽損失,甚至吃上官司,我...
摘要:但是在轉化中,浮點數轉化為二進制后,不會精確等于十進制的。一般情況下,只要簡單地將最終顯示的結果用四舍五入到所期望的十進制位數,就會得到期望的最終結果。四舍五入內建函數。在中的第二個數,表示要保留的小數位數,返回值是一個四舍五入之后的數值。 數字 基本類型 首先,進入Python交互模式中: //整數 >>> 3 3 //長整數 >>> 3333333333333333333333...
摘要:方法使用定點表示法來格式化一個數,會對結果進行四舍五入。該數值在必要時進行四舍五入,另外在必要時會用來填充小數部分,以便小數部分有指定的位數。如果數值大于,該方法會簡單調用并返回一個指數記數法格式的字符串。在環境中,只能是之間,測試版本為。 showImg(https://segmentfault.com/img/remote/1460000011913134?w=768&h=521)...
閱讀 3407·2021-11-25 09:43
閱讀 2294·2021-09-06 15:02
閱讀 3538·2021-08-18 10:21
閱讀 3340·2019-08-30 15:55
閱讀 2343·2019-08-29 17:06
閱讀 3534·2019-08-29 16:59
閱讀 962·2019-08-29 13:47
閱讀 2756·2019-08-26 13:24