Loading [MathJax]/extensions/tex2jax.js
Parallel numerical verification of the σ_odd problem  October 6, 2018
All Classes Namespaces Files Functions Variables Typedefs Macros
divisors.cpp
Go to the documentation of this file.
1 /* -*- coding: latin-1 -*- */
2 /** \file common/sigmaodd/divisors.cpp (December 20, 2017)
3  *
4  * GPLv3 --- Copyright (C) 2017 Olivier Pirson
5  * http://www.opimedia.be/
6  */
7 
8 // \cond
9 #include <cassert>
10 #include <cfenv>
11 #include <cstdlib>
12 
13 #include <utility>
14 // \endcond
15 
16 #include "../helper/helper.hpp"
17 #include "divisors.hpp"
18 #include "harmonic.hpp"
19 #include "primes.hpp"
20 
21 
22 namespace sigmaodd {
23 
24  /* *******************
25  * Private prototype *
26  *********************/
27 
28  std::vector<nat_type>
30 
31 
32 
33  /* ******************
34  * Private function *
35  ********************/
36 
37  /** \brief
38  * Return a list of factors such that all factors are coprimes
39  * and divide a*b,
40  * and these factors are (possibly) sufficient for coprime_factor_exps().
41  *
42  * @param a > 1
43  * @param b > 1
44  */
45  std::vector<nat_type>
47  assert(a > 1);
48  assert(b > 1);
49 
50  // Preliminary special cases
51  if (a == b) {
52  return std::vector<nat_type>{a};
53  }
54 
55  if (a > b) {
56  std::swap(a, b);
57  }
58 
59 
60  // Preliminary simplifications
61  do {
62  while (is_divide(a, b)) {
63  b /= a;
64  }
65 
66  if (b == 1) {
67  assert(a != 1);
68 
69  return std::vector<nat_type>{a};
70  }
71 
72  if (a > b) {
73  std::swap(a, b);
74  }
75  else {
76  break;
77  }
78  } while (is_divide(a, b));
79 
80  assert(a > 1);
81  assert(b > 1);
82  assert(a < b);
83 
84 
85  // Identify {a, b} coprime or divide a and b by their GCD
86  const nat_type d = gcd(a, b);
87 
88  if (d == 1) { // {a, b} are coprimes
89  return std::vector<nat_type>{a, b};
90  }
91  else { // {a, b} are NOT coprimes
92  do {
93  a /= d;
94  } while (is_divide(d, a));
95 
96  do {
97  b /= d;
98  } while (is_divide(d, b));
99 
100  if (a > b) {
101  std::swap(a, b);
102  }
103 
104  if (a == 1) {
105  return std::vector<nat_type>{d, b};
106  }
107 
108  assert(a > 1);
109  assert(b > 1);
110  assert(a < b);
111 
112  // These {a, b} are coprimes
113 
114  bool is_coprime_d_a = is_coprime(d, a);
115  bool is_coprime_d_b = is_coprime(d, b);
116 
117  if (is_coprime_d_a && is_coprime_d_b) { // {d, a, b} are coprime
118  return std::vector<nat_type>{d, a, b};
119  }
120  else { // {d, a} are NOT coprime and/or {d, b} are NOT coprime
121  if (is_coprime_d_b) {
122  std::swap(is_coprime_d_a, is_coprime_d_b);
123  std::swap(a, b);
124  }
125 
126  if (is_coprime_d_a) { // {d, a} are coprime and {d, b} are NOT coprime
127  std::vector<nat_type> factors = (d == b
128  ? std::vector<nat_type>{b}
129  : coprime_factors_(d, b)); // d*b < initial product
130 
131  factors.push_back(a);
132 
133  return factors;
134  }
135  else { // {d, a} and {d, b} are NOT coprime
136  return coprime_factors_(d, a*b); // d*a*b < initial product
137  }
138  }
139  }
140  }
141 
142 
143 
144  /* ***********
145  * Functions *
146  *************/
147  std::ostream&
148  operator<<(std::ostream &out, const FactorExp &factor_exp) {
149  assert(factor_exp.exp != 0);
150 
151  out << factor_exp.factor;
152  if (factor_exp.exp > 1) {
153  out << '^' << factor_exp.exp;
154  }
155 
156  return out;
157  }
158 
159 
160 
161  std::vector<FactorExp>
163  assert(a > 1);
164  assert(b > 1);
165 
166  nat_type n = a*b;
167 
168  std::vector<FactorExp> coprimes;
169 
170  for (nat_type factor : coprime_factors_(a, b)) {
171  // Use collected coprime factors to rebuild product
172  assert(factor != 1);
173  assert(factor < a*b);
174 
175  unsigned int alpha = 0;
176 
177  while (is_divide(factor, n)) {
178  n /= factor;
179  ++alpha;
180  }
181 
182  // factor^alpha is a (possibly) correct coprime factor
183  coprimes.push_back({factor, alpha});
184  }
185 
186  if (n != 1) { // the collected factors don't complete divide a*b in coprime factors
187  for (auto it = coprimes.begin(); it < coprimes.end(); ++it) {
188  if (!is_coprime(it->factor, n)) {
189  // the remain factor is NOT coprime with this collected coprime factor, heuristic failed
190  return std::vector<FactorExp>();
191  }
192  }
193 
194  // the remain factor is coprime with collected coprime factors
195  coprimes.push_back({n, 1});
196  }
197 
198  assert(!coprimes.empty());
199 
200  return (coprimes.size() > 1
201  ? coprimes // success
202  : std::vector<FactorExp>()); // heuristic failed to find at least two coprime factors
203  }
204 
205 
206  std::pair<nat_type, unsigned int>
208  assert(n != 0);
209  assert(d > 1);
210 
211  unsigned int alpha = 0;
212 
213  while (is_divide(d, n)) {
214  n /= d;
215  ++alpha;
216  }
217 
218  return std::make_pair(n, alpha);
219  }
220 
221 
222  nat_type
224  if (is_even(n)) {
225  return (n != 0
226  ? 2
227  : 1);
228  }
229  else {
230  const nat_type sqrt_n = floor_square_root(n);
231 
232  // Search prime divisor present in the precalculated table
233  for (unsigned int i = 0; i < odd_primes_table_nb(); ++i) {
234  const nat_type prime = odd_primes_table_by_index(i);
235 
236  if (is_divide(prime, n)) {
237  return prime;
238  }
239  else if (prime > sqrt_n) { // n is prime
240  return n;
241  }
242  }
243 
244 #ifdef PRIME16
245  // Search other prime divisor by iteration on potential primes
246  assert(odd_primes_table_last() % potential_prime_offsets_table_modulo() == 1);
247 
249 
250  while (p < sqrt_n) {
251  for (unsigned int i = 0; i < potential_prime_offsets_table_nb(); ++i) {
252  p += potential_prime_offsets_table_by_index(i);
253 
254  if (is_divide(p, n)) {
255  return p;
256  }
257  }
258  }
259 #endif
260 
261  return n; // n is prime
262  }
263  }
264 
265 
266  bool
268  if (n >= 18446744065119617025ul) { // >= (2^(64/2) - 1)^2 = 18446744065119617025
269  return (n == 18446744065119617025ul);
270  }
271  else {
272  nat_type sqrt_n = static_cast<nat_type>(floor(sqrt(static_cast<double>(n))));
273 
274  /* Correct possible rounding error due to floating point computation */
275  if (square(sqrt_n) < n) {
276  do {
277  ++sqrt_n;
278  } while (square(sqrt_n) < n);
279  }
280  else {
281  while (square(sqrt_n) > n) {
282  --sqrt_n;
283  }
284  }
285 
286  return (square(sqrt_n) == n);
287  }
288  }
289 
290 
291  nat_type
293  assert(n != 0);
294 
295  return pollard_rho(n, static_cast<unsigned int>(std::rand()) % n, floor_square_root(n));
296  }
297 
298 
299  nat_type
300  pollard_rho(nat_type n, nat_type random, nat_type max_iteration) {
301  assert(n != 0);
302  assert(random < n);
303 
304  /*
305  Adapted from:
306  Thomas H. Cormen, Charles E. Leiserson, Ron Rivest, and Clifford Stein.
307  Introduction to Algorithms. 3rd 2009
308  */
309  nat_type x = random;
310  nat_type y = x;
311  nat_type k = 2;
312 
313  for (nat_type i = 1; i < max_iteration; ++i) {
314  x = (x != 0
315  ? static_cast<nat_type>((static_cast<tmp_uint128_type>(x)*x - 1) % n)
316  : n - 1);
317 
318  if (is_even(i)) {
319  const nat_type d = gcd((y >= x
320  ? y - x
321  : x - y), n);
322 
323  if ((d != 1) && (d != n)) {
324  assert(is_divide(d, n));
325 
326  return d;
327  }
328  }
329 
330  if (i == k) {
331  y = x;
332  k <<= 1;
333  }
334  }
335 
336  return 0;
337  }
338 
339 
340  nat_type
342  assert(n != 0);
343 
344  while (nb_tries-- > 0) {
345  const nat_type divisor = pollard_rho(n);
346 
347  if (divisor != 0) {
348  return divisor;
349  }
350  }
351 
352  return 0;
353  }
354 
355 
356  nat_type
358  assert(n != 0);
359 
360  const std::pair<nat_type, unsigned int> result_alpha = divide_until_odd_nb(n);
361 
362  n = result_alpha.first;
363 
364  nat_type sum = (static_cast<nat_type>(1) << (result_alpha.second + 1)) - 1;
365  nat_type sqrt_n = floor_square_root(n);
366 
367  // Search prime factors present in the precalculated table
368  for (unsigned int i = 0; (n > 1) && (i < odd_primes_table_nb()); ++i) {
369  const nat_type prime = odd_primes_table_by_index(i);
370 
371  if (prime > sqrt_n) { // remain n is prime
372  return sum*(n + 1);
373  }
374 
375  unsigned int alpha = 0;
376 
377  while (is_divide(prime, n)) {
378  n /= prime;
379  sqrt_n = floor_square_root(n);
380  ++alpha;
381  }
382 
383  if (alpha > 0) {
384  sum *= sum_geometric_progression_strict(prime, alpha);
385  }
386  }
387 
388 #ifdef PRIME16
389  // Search other prime factors by iteration on potential primes
390  assert(odd_primes_table_last() % potential_prime_offsets_table_modulo() == 1);
391 
393 
394  while (n > 1) {
395  for (unsigned int i = 0; i < potential_prime_offsets_table_nb(); ++i) {
396  p += potential_prime_offsets_table_by_index(i);
397 
398  if (p > sqrt_n) { // remain n is prime
399  return sum*(n + 1);
400  }
401 
402  unsigned int alpha = 0;
403 
404  while (is_divide(p, n)) {
405  n /= p;
406  sqrt_n = floor_square_root(n);
407  ++alpha;
408  }
409 
410  if (alpha > 0) {
411  sum *= sum_geometric_progression_strict(p, alpha);
412  }
413  }
414  }
415 #endif
416 
417  return sum;
418  }
419 
420 
421  nat_type
423  assert(n != 0);
424 
425  const nat_type sqrt_n = floor_square_root(n);
426 
427  nat_type sum = 0;
428 
429  for (nat_type i = 1; i <= sqrt_n; ++i) {
430  if (is_divide(i, n)) {
431  sum += i + n/i;
432  }
433  }
434 
435  if (square(sqrt_n) == n) {
436  sum -= sqrt_n;
437  }
438 
439  return sum;
440  }
441 
442 
443  nat_type
445  assert(n != 0);
446 
447  n = divide_until_odd(n);
448 
449  nat_type sum = 1;
450  nat_type sqrt_n = floor_square_root(n);
451 
452  // Search prime factors present in the precalculated table
453  for (unsigned int i = 0; (n > 1) && (i < odd_primes_table_nb()); ++i) {
454  const nat_type prime = odd_primes_table_by_index(i);
455 
456  if (prime > sqrt_n) { // remain n is prime
457  return sum*(n + 1);
458  }
459 
460  unsigned int alpha = 0;
461 
462  while (is_divide(prime, n)) {
463  n /= prime;
464  sqrt_n = floor_square_root(n);
465  ++alpha;
466  }
467 
468  if (alpha > 0) {
469  sum *= sum_geometric_progression_strict(prime, alpha);
470  }
471  }
472 
473 #ifdef PRIME16
474  // Search other prime factors by iteration on potential primes
475  assert(odd_primes_table_last() % potential_prime_offsets_table_modulo() == 1);
476 
478 
479  while (n > 1) {
480  for (unsigned int i = 0; i < potential_prime_offsets_table_nb(); ++i) {
481  p += potential_prime_offsets_table_by_index(i);
482 
483  if (p > sqrt_n) { // remain n is prime
484  return sum*(n + 1);
485  }
486 
487  unsigned int alpha = 0;
488 
489  while (is_divide(p, n)) {
490  n /= p;
491  sqrt_n = floor_square_root(n);
492  ++alpha;
493  }
494 
495  if (alpha > 0) {
496  sum *= sum_geometric_progression_strict(p, alpha);
497  }
498  }
499  }
500 #endif
501 
502  return sum;
503  }
504 
505 
506  nat_type
508  assert(n != 0);
509 
510  n = divide_until_odd(n);
511 
512  const nat_type sqrt_n = floor_square_root(n);
513 
514  nat_type sum = 0;
515 
516  for (nat_type i = 1; i <= sqrt_n; i += 2) {
517  if (is_divide(i, n)) {
518  sum += i + n/i;
519  }
520  }
521 
522  if (square(sqrt_n) == n) {
523  sum -= sqrt_n;
524  }
525 
526  return sum;
527  }
528 
529 
530  nat_type
532  assert(n != 0);
533 
534  n = divide_until_odd(n);
535 
537 
538  if (n <= 10) {
539  return bound;
540  }
541 
542  const nat_type sqrt_n = floor_square_root(n);
543  double diff = 0;
544 
545  const int round = fegetround();
546 
547  fesetround(FE_DOWNWARD);
548 
549  unsigned int i = 0;
550 
551  if (true) {
552  // Remove until first prime divisor
553  for ( ; i < 10; ++i) {
554  const nat_type prime = odd_primes_table_by_index(i);
555 
556  if (prime > sqrt_n) {
557  fesetround(round);
558 
559  return n + 1;
560  }
561 
562  if (is_divide(prime, n)) {
563  const nat_type k = prime - 2;
564 
565  // ???
566  // bound = (k + 1)*k/2 - 1 + n - harmonic(k);
567  for (nat_type d = 3; d <= k; d += 2) {
568  bound -= d;
569  diff += static_cast<double>(n)/static_cast<double>(d);
570  }
571 
572  break;
573  }
574  }
575  }
576 
577  if (true) {
578  // Remove if not divide
579  for ( ; i < 10; ++i) {
580  const nat_type prime = odd_primes_table_by_index(i);
581 
582  if (prime > sqrt_n) {
583  break;
584  }
585 
586  if (!is_divide(prime, n)) {
587  bound -= prime;
588  diff += static_cast<double>(n)/static_cast<double>(prime);
589  }
590  }
591  }
592 
593  fesetround(round);
594 
595  assert(diff >= 0);
596 
597  return bound - static_cast<nat_type>(std::floor(diff));
598  }
599 
600 
601  nat_type
603  assert(n != 0);
604 
605  // ????????????????? n = divide_until_odd(n); // ???? virer ???
606 
607  if (n > 1) {
608  const nat_type sqrt_n = floor_square_root(n);
609 
610  // floor(sqrt(n - 1))
611  const nat_type sqrt_n1 = (square(sqrt_n) == n
612  ? sqrt_n - 1
613  : sqrt_n);
614 
615  // ((S + 1)/2)^2 + n (H_S1 - 1/2 H_{S1/2}) with S = floor(sqrt(n)) and S1 = floor(sqrt(n - 1))
616  const int round = fegetround();
617 
618  fesetround(FE_UPWARD);
619 
620  const nat_type harmonic_part
621  = static_cast<nat_type>(std::floor((diff_half_harmonic_upper_bound(sqrt_n1))
622  * static_cast<double>(n)));
623 
624  fesetround(round);
625 
626  return square((sqrt_n + 1)/2) + harmonic_part;
627  }
628  else {
629  return 1;
630  }
631  }
632 
633 
634  nat_type
636  assert(n != 0);
637  assert(is_odd(n));
638 
639  if (n > 1) {
640  const nat_type sqrt_n = floor_square_root(n);
641 
642  // floor(sqrt(n - 1))
643  const nat_type sqrt_n1 = (square(sqrt_n) == n
644  ? sqrt_n - 1
645  : sqrt_n);
646 
647  // ((S + 1)/2)^2 + n (H_S1 - 1/2 H_{S1/2}) with S = floor(sqrt(n)) and S1 = floor(sqrt(n - 1))
648  const int round = fegetround();
649 
650  fesetround(FE_UPWARD);
651 
652  const nat_type harmonic_part
653  = static_cast<nat_type>(std::ceil(diff_half_harmonic_upper_bound(sqrt_n1))) * n;
654 
655  fesetround(round);
656 
657  return square((sqrt_n + 1)/2) + harmonic_part;
658  }
659  else {
660  return 1;
661  }
662  }
663 
664 
665  nat_type
667  assert(n != 0);
668  assert(is_odd(n));
669 
670  assert(is_odd(k));
671  assert(k <= floor_square_root(n));
672 
673 #ifndef NDEBUG
674  for (nat_type i = 3; i <= k; i += 2) {
675  assert(!is_divide(i, n));
676  }
677 #endif
678 
680  double diff = diff_half_harmonic_upper_bound(k); // ???
681 
682  bound += n + 1;
683  bound -= square(k + 1)/4;
684  bound -= static_cast<nat_type>((std::floor(static_cast<double>(n)*diff)));
685 
686  return bound;
687  }
688 
689 } // namespace sigmaodd
nat_type sum_odd_divisors__naive(nat_type n)
Calculates the sum of odd divisors of n by the naive method and returns it.
Definition: divisors.cpp:507
constexpr nat_type sum_geometric_progression_strict(nat_type r, unsigned int k)
Return sum_geometric_progression(r, k) but only for r > 1.
nat_type floor_square_root(nat_type n)
Return the square root of n rounded to below.
Definition: helper.cpp:76
uint64_t nat_type
Type for natural number used in all code, on 64 bits.
Definition: helper.hpp:33
Structure to represent a factor with its exponent.
Definition: divisors.hpp:33
prime_type odd_primes_table_last()
Return the last odd prime number in the precalculated table.
constexpr bool is_odd(nat_type n)
Return true iff n is odd.
nat_type sum_odd_divisors_upper_bound__DeTemple_ceil(nat_type n)
Return an upper bound of sum odd divisors of n using the DeTemple inequalities. ???
Definition: divisors.cpp:635
nat_type pollard_rho_repeat(nat_type n, nat_type nb_tries)
Try pollard_rho(n) a maximum of nb_tries times and return 0 or the first divisor find.
Definition: divisors.cpp:341
nat_type sum_divisors__naive(nat_type n)
Calculates the sum of all divisors of n by the naive method and returns it.
Definition: divisors.cpp:422
std::pair< nat_type, unsigned int > divide_until_odd_nb(nat_type n)
Divide n by 2 until the result is odd, and return (result, number of divisions).
nat_type divide_until_odd(nat_type n)
Return n divided by 2 until the result is odd.
constexpr bool is_even(nat_type n)
Return true iff n is even.
nat_type first_divisor(nat_type n)
Return the first divisor of n > 1 (or 1 if n <= 1)
Definition: divisors.cpp:223
unsigned int exp
Definition: divisors.hpp:35
bool is_square(nat_type n)
Return true iff n is a perfect square.
Definition: divisors.cpp:267
double diff_half_harmonic_upper_bound(nat_type a, nat_type b)
Return an upper bound of H_a - 1/2 H_b.
Definition: harmonic.cpp:42
std::vector< nat_type > coprime_factors_(nat_type a, nat_type b)
Return a list of factors such that all factors are coprimes and divide a*b, and these factors are (po...
Definition: divisors.cpp:46
A lot of functions and stuffs to deal the sigma_odd problem and related stuffs.
Definition: divisors.cpp:22
std::ostream & operator<<(std::ostream &out, const FactorExp &factor_exp)
Return "factor^exponent" representation of factor_exp.
Definition: divisors.cpp:148
constexpr bool is_divide(nat_type d, nat_type n)
Return true iff d divide n, i.e. if n is divisible by d.
Functions to access to tables of precaculated prime numbers and offsets to iterate on possible prime ...
nat_type sum_odd_divisors__factorize(nat_type n)
Calculates the sum of odd divisors of n by the factorization method and returns it.
Definition: divisors.cpp:444
unsigned __int128 tmp_uint128_type
Type double size for some temporary calculation.
Definition: helper.hpp:42
Function to calculate harmonic number H_n = 1 + 1/2 + 1/3 + 1/4 + ... + 1/n and some variants and upp...
nat_type sum_odd_divisors_upper_bound(nat_type n)
Return an upper bound of sum odd divisors.
Definition: divisors.cpp:531
constexpr nat_type gcd(nat_type a, nat_type b)
Return the Greatest Common Divisor of a and b.
nat_type sum_divisors__factorize(nat_type n)
Calculates the sum of all divisors of n by the factorization method and returns it.
Definition: divisors.cpp:357
prime_type odd_primes_table_by_index(unsigned int i)
Return the (i + 1)th odd prime number from the precalculated table.
std::vector< FactorExp > coprime_factor_exps(nat_type a, nat_type b)
Heuristic to return a list of factors with their exponents such that all factors are coprimes and the...
Definition: divisors.cpp:162
constexpr unsigned int odd_primes_table_nb()
Return the number of odd prime numbers in the precalculated table.
constexpr double square(double x)
Return x*x.
const double alpha
Definition: harmonic.cpp:24
Functions in link with divisor notion: sum of divisors, factorization, GCD, coprime, ...
std::pair< nat_type, unsigned int > divide_until_nb(nat_type n, nat_type d)
Divide n by d until the result is not divisible by d, and return (result, number of divisions)...
Definition: divisors.cpp:207
constexpr nat_type is_coprime(nat_type a, nat_type b)
Return true iff a and b are coprime (relatively prime).
nat_type sum_odd_divisors_upper_bound__DeTemple(nat_type n)
Return an upper bound of sum odd divisors of n using the DeTemple inequalities.
Definition: divisors.cpp:602
nat_type pollard_rho(nat_type n)
Return pollard_rho(n, rand() % n, floor square root of n).
Definition: divisors.cpp:292