Browse Source

add method

Looly 4 years ago
parent
commit
87813ae898

+ 2 - 1
CHANGELOG.md

@@ -3,7 +3,7 @@
 
 -------------------------------------------------------------------------------------------------------------
 
-# 5.6.0 (2021-03-05)
+# 5.6.0 (2021-03-07)
 
 ### 新特性
 * 【poi    】     重要:不再兼容POI-3.x,增加兼容POI-5.x(issue#I35J6B@Gitee)
@@ -12,6 +12,7 @@
 * 【crypto 】     增加PBKDF2(issue#1416@Github)
 * 【core   】     增加FuncKeyMap(issue#1402@Github)
 * 【core   】     增加StrMatcher(issue#1379@Github)
+* 【core   】     NumberUtil增加factorial针对BigInterger方法(issue#1379@Github)
 
 ### Bug修复
 * 【socket 】     修复Client创建失败资源未释放问题。

+ 53 - 1
hutool-core/src/main/java/cn/hutool/core/util/NumberUtil.java

@@ -1429,9 +1429,61 @@ public class NumberUtil {
 	// ------------------------------------------------------------------------------------------- others
 
 	/**
+	 * 计算阶乘
+	 * <p>
+	 * n! = n * (n-1) * ... * 2 * 1
+	 * </p>
+	 *
+	 * @param n 阶乘起始
+	 * @return 结果
+	 * @since 5.6.0
+	 */
+	public static BigInteger factorial(BigInteger n) {
+		if(n.equals(BigInteger.ZERO)){
+			return BigInteger.ONE;
+		}
+		return factorial(n, BigInteger.ZERO);
+	}
+
+	/**
+	 * 计算范围阶乘
+	 * <p>
+	 * factorial(start, end) = start * (start - 1) * ... * (end + 1)
+	 * </p>
+	 *
+	 * @param start 阶乘起始(包含)
+	 * @param end   阶乘结束,必须小于起始(不包括)
+	 * @return 结果
+	 * @since 5.6.0
+	 */
+	public static BigInteger factorial(BigInteger start, BigInteger end) {
+		Assert.notNull(start, "Factorial start must be not null!");
+		Assert.notNull(end, "Factorial end must be not null!");
+		if(start.compareTo(BigInteger.ZERO) < 0 || end.compareTo(BigInteger.ZERO) < 0){
+			throw new IllegalArgumentException(StrUtil.format("Factorial start and end both must be > 0, but got start={}, end={}", start, end));
+		}
+
+		if (start.equals(BigInteger.ZERO)){
+			start = BigInteger.ONE;
+		}
+
+		if(end.compareTo(BigInteger.ONE) < 0){
+			end = BigInteger.ONE;
+		}
+
+		BigInteger result = start;
+		end = end.add(BigInteger.ONE);
+		while(start.compareTo(end) > 0) {
+			start = start.subtract(BigInteger.ONE);
+			result = result.multiply(start);
+		}
+		return result;
+	}
+
+	/**
 	 * 计算范围阶乘
 	 * <p>
-	 * factorial(start, end) = start * (start - 1) * ... * (end - 1)
+	 * factorial(start, end) = start * (start - 1) * ... * (end + 1)
 	 * </p>
 	 *
 	 * @param start 阶乘起始(包含)

+ 43 - 24
hutool-core/src/test/java/cn/hutool/core/util/NumberUtilTest.java

@@ -5,17 +5,18 @@ import org.junit.Assert;
 import org.junit.Test;
 
 import java.math.BigDecimal;
+import java.math.BigInteger;
 import java.math.RoundingMode;
 import java.util.Set;
 
 /**
  * {@link NumberUtil} 单元测试类
- * 
+ *
  * @author Looly
  *
  */
 public class NumberUtilTest {
-	
+
 	@Test
 	public void addTest() {
 		Float a = 3.15f;
@@ -23,7 +24,7 @@ public class NumberUtilTest {
 		double result = NumberUtil.add(a, b).doubleValue();
 		Assert.assertEquals(7.37, result, 2);
 	}
-	
+
 	@Test
 	public void addTest2() {
 		double a = 3.15f;
@@ -31,7 +32,7 @@ public class NumberUtilTest {
 		double result = NumberUtil.add(a, b);
 		Assert.assertEquals(7.37, result, 2);
 	}
-	
+
 	@Test
 	public void addTest3() {
 		float a = 3.15f;
@@ -39,13 +40,13 @@ public class NumberUtilTest {
 		double result = NumberUtil.add(a, b, a, b).doubleValue();
 		Assert.assertEquals(14.74, result, 2);
 	}
-	
+
 	@Test
 	public void addTest4() {
 		BigDecimal result = NumberUtil.add(new BigDecimal("133"), new BigDecimal("331"));
 		Assert.assertEquals(new BigDecimal("464"), result);
 	}
-	
+
 	@Test
 	public void isIntegerTest() {
 		Assert.assertTrue(NumberUtil.isInteger("-12"));
@@ -54,7 +55,7 @@ public class NumberUtilTest {
 		Assert.assertTrue(NumberUtil.isInteger("0"));
 		Assert.assertFalse(NumberUtil.isInteger("23.4"));
 	}
-	
+
 	@Test
 	public void isLongTest() {
 		Assert.assertTrue(NumberUtil.isLong("-12"));
@@ -63,7 +64,7 @@ public class NumberUtilTest {
 		Assert.assertTrue(NumberUtil.isLong("0"));
 		Assert.assertFalse(NumberUtil.isLong("23.4"));
 	}
-	
+
 	@Test
 	public void isNumberTest() {
 		Assert.assertTrue(NumberUtil.isNumber("28.55"));
@@ -78,7 +79,7 @@ public class NumberUtilTest {
 		double result = NumberUtil.div(0, 1);
 		Assert.assertEquals(0.0, result, 0);
 	}
-	
+
 	@Test
 	public void roundTest() {
 
@@ -93,7 +94,7 @@ public class NumberUtilTest {
 		String round4 = NumberUtil.roundStr("2.675", 2);
 		Assert.assertEquals("2.68", round3);
 		Assert.assertEquals("2.68", round4);
-		
+
 		// 四舍六入五成双
 		String round31 = NumberUtil.roundStr(4.245, 2, RoundingMode.HALF_EVEN);
 		String round41 = NumberUtil.roundStr("4.2451", 2, RoundingMode.HALF_EVEN);
@@ -105,7 +106,7 @@ public class NumberUtilTest {
 		String round6 = NumberUtil.roundStr("2.6005", 2);
 		Assert.assertEquals("2.60", round5);
 		Assert.assertEquals("2.60", round6);
-		
+
 		// 补0
 		String round7 = NumberUtil.roundStr(2.600, 2);
 		String round8 = NumberUtil.roundStr("2.600", 2);
@@ -118,7 +119,7 @@ public class NumberUtilTest {
 		String roundStr = NumberUtil.roundStr(2.647, 2);
 		Assert.assertEquals(roundStr, "2.65");
 	}
-	
+
 	@Test
 	public void roundHalfEvenTest() {
 		String roundStr = NumberUtil.roundHalfEven(4.245, 2).toString();
@@ -129,7 +130,7 @@ public class NumberUtilTest {
 		Assert.assertEquals(roundStr, "4.25");
 		roundStr = NumberUtil.roundHalfEven(4.2250, 2).toString();
 		Assert.assertEquals(roundStr, "4.22");
-		
+
 		roundStr = NumberUtil.roundHalfEven(1.2050, 2).toString();
 		Assert.assertEquals(roundStr, "1.20");
 		roundStr = NumberUtil.roundHalfEven(1.2150, 2).toString();
@@ -159,14 +160,14 @@ public class NumberUtilTest {
 		String format = NumberUtil.decimalFormat(",###", c);
 		Assert.assertEquals("299,792,458", format);
 	}
-	
+
 	@Test
 	public void decimalFormatMoneyTest() {
 		double c = 299792400.543534534;
-		
+
 		String format = NumberUtil.decimalFormatMoney(c);
 		Assert.assertEquals("299,792,400.54", format);
-		
+
 		double value = 0.5;
 		String money = NumberUtil.decimalFormatMoney(value);
 		Assert.assertEquals("0.50", money);
@@ -176,17 +177,17 @@ public class NumberUtilTest {
 	public void equalsTest() {
 		Assert.assertTrue(NumberUtil.equals(new BigDecimal("0.00"), BigDecimal.ZERO));
 	}
-	
+
 	@Test
 	public void formatPercentTest() {
 		String str = NumberUtil.formatPercent(0.33543545, 2);
 		Assert.assertEquals("33.54%", str);
 	}
-	
+
 	@Test
 	public void toBigDecimalTest() {
 		double a = 3.14;
-				
+
 		BigDecimal bigDecimal = NumberUtil.toBigDecimal(a);
 		Assert.assertEquals("3.14", bigDecimal.toString());
 
@@ -208,7 +209,7 @@ public class NumberUtilTest {
 		int min = NumberUtil.min(5,4,3,6,1);
 		Assert.assertEquals(1, min);
 	}
-	
+
 	@Test
 	public void parseIntTest() {
 		int number = NumberUtil.parseInt("0xFF");
@@ -258,7 +259,7 @@ public class NumberUtilTest {
 		Number v2 = NumberUtil.parseNumber("1,482.00D");
 		Assert.assertEquals(1482L, v2);
 	}
-	
+
 	@Test
 	public void parseLongTest() {
 		long number = NumberUtil.parseLong("0xFF");
@@ -303,18 +304,36 @@ public class NumberUtilTest {
 		Assert.assertEquals(120, factorial);
 		factorial = NumberUtil.factorial(5, 1);
 		Assert.assertEquals(120, factorial);
-    
+
 		Assert.assertEquals(5, NumberUtil.factorial(5, 4));
 		Assert.assertEquals(2432902008176640000L, NumberUtil.factorial(20, 0));
 	}
 
 	@Test
+	public void factorialTest2(){
+		long factorial = NumberUtil.factorial(new BigInteger("0")).longValue();
+		Assert.assertEquals(1, factorial);
+
+		Assert.assertEquals(1L, NumberUtil.factorial(new BigInteger("1")).longValue());
+		Assert.assertEquals(1307674368000L, NumberUtil.factorial(new BigInteger("15")).longValue());
+		Assert.assertEquals(2432902008176640000L, NumberUtil.factorial(20));
+
+		factorial = NumberUtil.factorial(new BigInteger("5"), new BigInteger("0")).longValue();
+		Assert.assertEquals(120, factorial);
+		factorial = NumberUtil.factorial(new BigInteger("5"), BigInteger.ONE).longValue();
+		Assert.assertEquals(120, factorial);
+
+		Assert.assertEquals(5, NumberUtil.factorial(new BigInteger("5"), new BigInteger("4")).longValue());
+		Assert.assertEquals(2432902008176640000L, NumberUtil.factorial(new BigInteger("20"), BigInteger.ZERO).longValue());
+	}
+
+	@Test
 	public void mulTest(){
 		final BigDecimal mul = NumberUtil.mul(new BigDecimal("10"), null);
 		Assert.assertEquals(BigDecimal.ZERO, mul);
 	}
-	
-	
+
+
 	@Test
 	public void isPowerOfTwoTest() {
 		Assert.assertFalse(NumberUtil.isPowerOfTwo(-1));