Counting square free numbers
Contents
In this article, we introduce an algorithm proposed by Jakub Pawlewicz [1] to count square free numbers not exceeding $n$ efficiently.
We first introduce a well-known algorithm with time complexity $\tilde{\mathcal{O}}(\sqrt{n})$. After that, we present a algorithm which is a modified version of first algorithm with time complexity $\tilde{\mathcal{O}}(n^{2/5})$ following from [1].
1. Definition
A square free number is an integer which is not divisible by a square of any integer greater than one. Apparently, an integer $d$ is a square free number iff $\mu(d) \neq 0$, where $\mu(d)$ is the Mobius function.
Let $S(n)$ denote the number of square free positive numbers less or equal to $n$, i.e.,
$$S(n) = \sum_{d=1}^{n} |\mu(d)|.$$
More information about square free numbers can be found at [2], [3].
2. The $\tilde{\mathcal{O}}(\sqrt{n})$ algorithm
2.1. Basic theorem
Theorem 1.
Suppose $P = \{p_1, p_2, \ldots, p_k\}$ is the set which consists of all prime numbers less or equal to $n$.
Let $A_i$ denote the set $\{m \le n: p_i^2 \mid m \}$.
Thus
Note that
so
For $Q_1 \neq Q_2$, it is clearly that
and any square free number less or equal to $n$ can be express as $\prod_{p \in Q} p$.
Thus
☐
2.2. Computing Mobius function
Following Theorem 1, we need to find the values of $\mu(d)$ for $d = 1, \ldots, K$, where $K = \lfloor \sqrt{n} \rfloor$. This can be done in time $\mathcal{O}(K \log\log K)$ using a sieve similar to the sieve of Eratosthenes. Following is my code in Python.
|
|
2.3. The algorithm
Now, our first algorithm is obvious.
|
|
Apparently, above algorithm has $\tilde{\mathcal{O}}(\sqrt{n})$ time complexity.
3. The modified algorithm
3.1. Establishing the new formula
For sufficiently large $D$, the value of $\left\lfloor \frac{n}{d^2} \right\rfloor$ with respect to $d > D$ will not change frequently. Based on this observation, we break the sum in (1) into two part: $$S(n) = S_1(n) + S_2(n),$$ where
Rewrite the sum $S_2(n)$ as:
Observe that, for $i \le \sqrt[3]{\frac{n}{4}}$,
Let denote $x_i = \sqrt{\frac{n}{i}}$, take $I \le \sqrt[3]{\frac{n}{4}}$ and $D = x_I$. Now the sum $S_2(n)$ can be simplified to:
where $M(x)$ is the Mertens function, i.e., $M(x) = \sum_{i=1}^{\lfloor x \rfloor}\mu(i)$.
3.2. Computing Mertens function
Applying the Mobius inversion formula, we know that $\sum_{d=1}^{x} M\left(\frac{x}{d}\right) = 1$, i.e.,
$$M(x) = 1 - \sum_{d=2}^{x} M\left( \frac{x}{d} \right).$$
Here, an important observation is that having all values $M(x/d)$ for $d \ge 2$, we are able to calculate $M(x)$ in time $\mathcal{O}(\sqrt{x})$. This is because there are at most $2\sqrt{x}$ different integers of the form $\lfloor x/d \rfloor$.
Moreover, to compute $M(x_i)$ we need the values $M(x_i / d)$ for $d \ge 2$. If $x_i / d \le D$ then $M(x_i/d)$ was determined during the computation of $S_1(n)$. If $x_i > D$ then $$\left\lfloor \frac{x_i}{d} \right\rfloor = \left\lfloor \frac{\left\lfloor \sqrt{\frac{n}{i}} \right\rfloor}{d} \right\rfloor = \left\lfloor \frac{\sqrt{\frac{n}{i}}}{d} \right\rfloor = \left\lfloor \sqrt{\frac{n}{d^2i}} \right\rfloor,$$ thus $M(x_i / d) = M(x_j)$ for $j = d^2 i$. Of course $j < I$, because otherwise $\sqrt{n/j} \le D$.
It worth noting that it is important to compute $M(x_i)$ in a decreasing order.
3.2. The algorithm
|
|
3.3. The complexity
Let us estimate the time complexity of above algorithm. Computing $S_1(n)$ has time complexity $\mathcal{O}(D \log\log D).$ The computation of $S_2(n)$ is dominated by the loop for computing $M(x_i)$. Therefore computing $S_2(n)$ has the time complexity:
due to computing $M(x_i)$ takes $\mathcal{O}(\sqrt{x_i})$ time.
If we choose $I = n^{1/5}$, then
4. Results
Following table is my run time of above two algorithms for different $n$.
Both Python functions are accelerated by numba.jit
.
$n$ | square_free | efficient_square_free |
---|---|---|
2**50 | 3.124 | 0.510 |
2**52 | 6.028 | 0.595 |
2**55 | 18.465 | 0.869 |
Reference
LastMod Feb 14, 2019
Email smsxgz at gmail dot com