Skip to content

Commit 36446d2

Browse files
Fix integer overflow in MobiusFunction squared-factor check
1 parent 346f591 commit 36446d2

2 files changed

Lines changed: 27 additions & 13 deletions

File tree

src/main/java/com/thealgorithms/maths/Prime/MobiusFunction.java

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -31,27 +31,28 @@ public static int mobius(int number) {
3131
throw new IllegalArgumentException("Number must be greater than zero.");
3232
}
3333

34-
if (number == 1) {
35-
// return 1 if number passed is less or is 1
36-
return 1;
37-
}
38-
3934
int primeFactorCount = 0;
35+
int remaining = number;
4036

41-
for (int i = 1; i <= number; i++) {
42-
// find prime factors of number
43-
if (number % i == 0 && PrimeCheck.isPrime(i)) {
44-
// check if number is divisible by square of prime factor
45-
if (number % (i * i) == 0) {
46-
// if number is divisible by square of prime factor
37+
/* Divide out every prime factor in turn. Trial division only has to run up to the square
38+
root of the remaining value, and the multiplication is widened to long so that the bound
39+
does not overflow for numbers close to Integer.MAX_VALUE. */
40+
for (int factor = 2; (long) factor * factor <= remaining; factor++) {
41+
if (remaining % factor == 0) {
42+
remaining /= factor;
43+
if (remaining % factor == 0) {
44+
// number is divisible by the square of this prime factor
4745
return 0;
4846
}
49-
/*increment primeFactorCount by 1
50-
if number is not divisible by square of found prime factor*/
5147
primeFactorCount++;
5248
}
5349
}
5450

51+
/* Whatever is left is either 1 or a single prime factor larger than the square root. */
52+
if (remaining > 1) {
53+
primeFactorCount++;
54+
}
55+
5556
return (primeFactorCount % 2 == 0) ? 1 : -1;
5657
}
5758
}

src/test/java/com/thealgorithms/maths/prime/MobiusFunctionTest.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
import com.thealgorithms.maths.Prime.MobiusFunction;
77
import org.junit.jupiter.api.Test;
8+
import org.junit.jupiter.params.ParameterizedTest;
9+
import org.junit.jupiter.params.provider.CsvSource;
810

911
class MobiusFunctionTest {
1012

@@ -152,4 +154,15 @@ void testMobiusFunction() {
152154
assertEquals(expectedValue, actualValue);
153155
}
154156
}
157+
158+
/**
159+
* Large inputs whose smallest square divisor test used to overflow, most notably
160+
* {@code Integer.MAX_VALUE}, whose square wraps around to 1 and made every number look like it
161+
* had a squared prime factor.
162+
*/
163+
@ParameterizedTest
164+
@CsvSource({"2147483647, -1", "2147483646, 0", "2147483645, -1", "2147483644, 0", "2147483629, -1", "2147395600, 0", "1073741824, 0", "1073741789, -1", "999999937, -1", "999999999, 0", "2146689000, 0"})
165+
void testMobiusForLargeNumbers(int number, int expected) {
166+
assertEquals(expected, MobiusFunction.mobius(number));
167+
}
155168
}

0 commit comments

Comments
 (0)