-
Notifications
You must be signed in to change notification settings - Fork 245
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Compute the sum of powers and the sum of divisors of an integer #2030
base: main
Are you sure you want to change the base?
Conversation
As for the example, you also have to modify It should check that the example gives a correct output. Rigorousness is not that important here. |
Add aliquot example in check_examples.sh Fix indentation to use spaces instead of tabs Fix test failure to use TEST_FUNCTION_FAIL macro
There is already I don't think |
I have the same exact opinion |
Yup, you're totally right. I embarrassingly didn't see that in the docs, and it certainly makes both Nonetheless, I think Perhaps it is warrented to migrate If you agree, I would
|
I don't think I'm a bit surprised that the exponent cutoff is as large as 100. One issue might be that you use Anyway, the k = 1 case in |
This pull request was inspired by a recent Numberphile video.
The main goal of this PR is the method
fmpz_sum_divisors_proper
which computes the sum of all proper divisors of an integerg
, i.e. all divisors including 1 but excludingg
itself, without multiplicities (e.g. 4 counts the divisor 2 only once).It does so by factorizing into primes and then counting multiplicities. Specifically, it uses the following well-known formula:
Let$k$ be a positive integer with prime factorization $k = p_{1}^{m_1} \dots p_{n}^{m_n}$ , where the $p_i$ are pairwise distinct primes. Denote by $S(n, e)$ the sum of powers of $n$ up to and including $n^e$ , i.e. $S(n, e) = \sum\limits_{i=1}^{e} n^{i}$ .$k$ (not necessarily proper) is equal to $\prod\limits_{i = 1}^{n} S(p_i, m_i)$ where the $p_i$ and $m_i$ are the primes and their multiplicities from the prime factor decomposition of $k$ .$k$ is negative, then this implementation performs the computation for $|k|$ and adds the sign in the end.
Then the sum of all divisors of
If
To compute this efficiently, this PR implements two methods to evaluate the function$S$ .$h_e(x) \coloneqq S(x,e)$ . The other method makes use of the identity $h_e(x) \cdot (x - 1) = x^{e+1} - 1$ .$O(e)$ time. Hence for large values of $e$ , the polynomial version will provide slightly better performance. Some quick and dirty testing on my machine shows that for $e \approx 100$ they are roughly equal.$e$ .
The first method is a Horner-style evaluation of the polynomial
Both methods have their benefits and their downsides. Assuming exponentiation is fast, the polynomial division trick executes in near constant time, but it requires a division. The Horner-style method only needs multiplications and small integer additions, but it takes
To "hide" this distinction from the user, an additional convenience method picks an algorithm automatically, based on the value of
To demonstrate the usefulness of this method, a new example program uses the function
fmpz_sum_divisors_proper
to compute the aliquot sequence of 138, which famously blows up to almost 180 billion before collapsing to 1.To the best of my knowledge, I followed the code style guidelines. I added documentation, and tests are provided for all functions (except for$k$ from
fmpz_sum_divisors_proper
because all it does is subtractfmpz_sum_divisors
).An analogue of
fmpz_sum_powers
might also be of interest for other types, likefmpq_t
or the arb types. Since the interfaces are pretty much identical, implementing similar functions in the other modules should be a trivial task (though it does lead to code duplication - tweaks in one module do not transfer to the other modules - which raises the question: Is there any plan on how to avoid such duplication? Something like templates in C++ or generics in C#. But that is a topic for another time).