From 77fbea15484ebd4aeb47bf1414cc29f70c4d2b41 Mon Sep 17 00:00:00 2001 From: Looly Date: Tue, 9 Dec 2025 15:50:23 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8DMathUtil.multiple=20=E6=96=B9?= =?UTF-8?q?=E6=B3=95=E5=9C=A8=E5=A4=A7=E6=95=B4=E6=95=B0=E4=B9=98=E6=B3=95?= =?UTF-8?q?=E8=BF=90=E7=AE=97=E4=B8=AD=E6=95=B4=E6=95=B0=E6=BA=A2=E5=87=BA?= =?UTF-8?q?=E9=A3=8E=E9=99=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/cn/hutool/v7/core/math/MathUtil.java | 10 +++- .../cn/hutool/v7/core/math/MathUtilTest.java | 48 ++++++++++++------- 2 files changed, 40 insertions(+), 18 deletions(-) diff --git a/hutool-core/src/main/java/cn/hutool/v7/core/math/MathUtil.java b/hutool-core/src/main/java/cn/hutool/v7/core/math/MathUtil.java index 5208e928c2..09e28ef1b3 100644 --- a/hutool-core/src/main/java/cn/hutool/v7/core/math/MathUtil.java +++ b/hutool-core/src/main/java/cn/hutool/v7/core/math/MathUtil.java @@ -339,7 +339,15 @@ public class MathUtil { * @return 最小公倍数 */ public static int multiple(final int m, final int n) { - return m * n / gcd(m, n); + // 先计算最大公约数 + final int gcd = gcd(m, n); + // 使用长整型避免溢出,再转换回整型 + final long result = (long) m / gcd * (long) n; + // 检查结果是否在int范围内 + if (result > Integer.MAX_VALUE || result < Integer.MIN_VALUE) { + throw new ArithmeticException("Integer overflow: " + m + " * " + n + " / " + gcd); + } + return (int) result; } private static int mathSubNode(final int selectNum, final int minNum) { diff --git a/hutool-core/src/test/java/cn/hutool/v7/core/math/MathUtilTest.java b/hutool-core/src/test/java/cn/hutool/v7/core/math/MathUtilTest.java index 7c30ba5d7a..04eef504a3 100644 --- a/hutool-core/src/test/java/cn/hutool/v7/core/math/MathUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/v7/core/math/MathUtilTest.java @@ -16,45 +16,59 @@ package cn.hutool.v7.core.math; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import java.math.BigInteger; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + public class MathUtilTest { @Test public void factorialTest(){ long factorial = MathUtil.factorial(0); - Assertions.assertEquals(1, factorial); + assertEquals(1, factorial); - Assertions.assertEquals(1L, MathUtil.factorial(1)); - Assertions.assertEquals(1307674368000L, MathUtil.factorial(15)); - Assertions.assertEquals(2432902008176640000L, MathUtil.factorial(20)); + assertEquals(1L, MathUtil.factorial(1)); + assertEquals(1307674368000L, MathUtil.factorial(15)); + assertEquals(2432902008176640000L, MathUtil.factorial(20)); factorial = MathUtil.factorial(5, 0); - Assertions.assertEquals(120, factorial); + assertEquals(120, factorial); factorial = MathUtil.factorial(5, 1); - Assertions.assertEquals(120, factorial); + assertEquals(120, factorial); - Assertions.assertEquals(5, MathUtil.factorial(5, 4)); - Assertions.assertEquals(2432902008176640000L, MathUtil.factorial(20, 0)); + assertEquals(5, MathUtil.factorial(5, 4)); + assertEquals(2432902008176640000L, MathUtil.factorial(20, 0)); } @Test public void factorialTest2(){ long factorial = MathUtil.factorial(new BigInteger("0")).longValue(); - Assertions.assertEquals(1, factorial); + assertEquals(1, factorial); - Assertions.assertEquals(1L, MathUtil.factorial(new BigInteger("1")).longValue()); - Assertions.assertEquals(1307674368000L, MathUtil.factorial(new BigInteger("15")).longValue()); - Assertions.assertEquals(2432902008176640000L, MathUtil.factorial(20)); + assertEquals(1L, MathUtil.factorial(new BigInteger("1")).longValue()); + assertEquals(1307674368000L, MathUtil.factorial(new BigInteger("15")).longValue()); + assertEquals(2432902008176640000L, MathUtil.factorial(20)); factorial = MathUtil.factorial(new BigInteger("5"), new BigInteger("0")).longValue(); - Assertions.assertEquals(120, factorial); + assertEquals(120, factorial); factorial = MathUtil.factorial(new BigInteger("5"), BigInteger.ONE).longValue(); - Assertions.assertEquals(120, factorial); + assertEquals(120, factorial); - Assertions.assertEquals(5, MathUtil.factorial(new BigInteger("5"), new BigInteger("4")).longValue()); - Assertions.assertEquals(2432902008176640000L, MathUtil.factorial(new BigInteger("20"), BigInteger.ZERO).longValue()); + assertEquals(5, MathUtil.factorial(new BigInteger("5"), new BigInteger("4")).longValue()); + assertEquals(2432902008176640000L, MathUtil.factorial(new BigInteger("20"), BigInteger.ZERO).longValue()); + } + + @Test + public void testMultipleOverflow() { + final int a = 500000; + final int b = 600000; + + // 原方法使用 a * b / gcd(a, b) 计算,a * b 会先溢出,得到最小公倍数为负数 + // 使用修改后的multiple方法,测试它是否能正确处理这种情况 + final int result = MathUtil.multiple(a, b); + // 验证结果必须是正数(两个正数的最小公倍数必须为正) + assertTrue(result > 0); } }