Commit 9e2bcfc8 authored by Nayuki's avatar Nayuki

P211: Sped up Java solution.

parent b0f57f12
...@@ -34,8 +34,9 @@ public final class p211 implements EulerSolution { ...@@ -34,8 +34,9 @@ public final class p211 implements EulerSolution {
} }
long sum = 0; long sum = 0;
SquareTester sqt = new SquareTester(3 * 5 * 7 * 11 * 13 * 17);
for (int i = 1; i < sigma2.length; i++) { for (int i = 1; i < sigma2.length; i++) {
if (isPerfectSquare(sigma2[i])) if (sqt.isPerfectSquare(sigma2[i]))
sum += i; sum += i;
} }
return Long.toString(sum); return Long.toString(sum);
...@@ -57,14 +58,45 @@ public final class p211 implements EulerSolution { ...@@ -57,14 +58,45 @@ public final class p211 implements EulerSolution {
} }
private static boolean isPerfectSquare(long x) {
long y = 0; // Consider the set of all squared natural numbers, i.e. {0, 1, 4, 9, 16, 25, ...}.
for (long i = 1L << 31; i != 0; i >>>= 1) { // When this set is viewed modulo some number n, usually not every residue is in the set.
y |= i; // For example, all squares modulo 3 is {0, 1} - so a perfect square modulo 3 is never 2.
if (y > 3037000499L || y * y > x) // By choosing a suitably large modulus, we can .
y ^= i; private static final class SquareTester {
// isResidue[i] is true iff there exists a natural number k such that k^2 = i mod modulus.
// Hence for any k, if isResidue[k] is false then k is not a perfect square.
private boolean[] isResidue;
// Any product of unique small prime numbers excluding 2 makes a good modulus
// that leads to fast tests. But the behavior is correct for any modulus >= 1.
public SquareTester(int modulus) {
if (modulus < 1)
throw new IllegalArgumentException();
isResidue = new boolean[modulus];
for (int i = 0; i < modulus; i++)
isResidue[(int)((long)i * i % modulus)] = true;
} }
return y * y == x;
public boolean isPerfectSquare(long x) {
// Reject many but not all numbers that aren't a perfect square.
// This speed optimization can be omitted without affecting correctness.
if (!isResidue[(int)(x % isResidue.length)])
return false;
// A complete algorithm for detecting squares
long y = 0;
for (long i = 1L << 31; i != 0; i >>>= 1) {
y |= i;
if (y > 3037000499L || y * y > x)
y ^= i;
}
return y * y == x;
}
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment