File: phi.cpp

package info (click to toggle)
primecount 8.0%2Bds-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,640 kB
  • sloc: cpp: 21,835; ansic: 121; sh: 99; makefile: 89
file content (143 lines) | stat: -rw-r--r-- 3,460 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
///
/// @file   phi.cpp
/// @brief  Test the partial sieve function phi(x, a)
///         which counts the numbers <= x that are not divisible
///         by any of the first a primes.
///
/// Copyright (C) 2021 Kim Walisch, <kim.walisch@gmail.com>
///
/// This file is distributed under the BSD License. See the COPYING
/// file in the top level directory.
///

#include <primecount.hpp>
#include <primecount-internal.hpp>
#include <primesieve.hpp>
#include <imath.hpp>

#include <stdint.h>
#include <iostream>
#include <cstdlib>
#include <vector>
#include <random>

using std::size_t;
using namespace primecount;

void check(size_t x, size_t a, size_t phi_xa, size_t cnt)
{
  bool OK = (phi_xa == cnt);
  std::cout << "phi(" << x << ", " << a << ") = " << phi_xa;
  std::cout << "   " << (OK ? "OK" : "ERROR") << "\n";
  if (!OK)
    std::exit(1);
}

void check2(size_t x, size_t a, size_t phi_xa, size_t cnt)
{
  if (phi_xa != cnt)
  {
    bool OK = (phi_xa == cnt);
    std::cout << "phi(" << x << ", " << a << ") = " << phi_xa;
    std::cout << "   " << (OK ? "OK" : "ERROR") << "\n";
    std::exit(1);
  }
  // Reduce logging because it is slow
  else if (a % 101 == 0)
  {
    bool OK = (phi_xa == cnt);
    std::cout << "phi(" << x << ", " << a << ") = " << phi_xa;
    std::cout << "   " << (OK ? "OK" : "ERROR") << "\n";
  }
}

int main()
{
  std::random_device rd;
  std::mt19937 gen(rd());

  {
    std::uniform_int_distribution<size_t> dist(20000000, 30000000);
    size_t size = dist(gen);
    size_t x = size - 1;
    size_t cnt = size - 1;
    primesieve::iterator it;
    std::vector<char> sieve(size, 1);

    // test with small a values
    for (size_t a = 1;; a++)
    {
      auto prime = it.next_prime();
      if (prime * prime > x)
        break;

      // remove primes[a] and its multiples
      for (auto j = prime; j <= x; j += prime)
      {
        cnt -= (sieve[j] == 1);
        sieve[j] = 0;
      }

      int64_t phi_xa = phi(x, a);
      check(x, a, phi_xa, cnt);
    }
  }

  {
    std::uniform_int_distribution<size_t> dist(100000, 200000);
    size_t size = dist(gen);
    size_t x = size - 1;
    size_t cnt = size - 1;
    primesieve::iterator it;
    std::vector<char> sieve(size, 1);

    // test with large a values
    for (size_t a = 1;; a++)
    {
      auto prime = it.next_prime();
      if (prime > x)
        break;

      // remove primes[a] and its multiples
      for (auto j = prime; j <= x; j += prime)
      {
        cnt -= (sieve[j] == 1);
        sieve[j] = 0;
      }

      int64_t phi_xa = phi(x, a);
      check2(x, a, phi_xa, cnt);
    }
  }

  {
    std::cout << "Testing phi(x, a) multi-threading" << std::endl;

    int64_t iters = 500;
    int64_t sum1 = 0;
    int64_t sum2 = 0;

    #pragma omp parallel for reduction(+: sum1)
    for (int64_t i = 0; i < iters; i++)
      sum1 += pi_legendre(10000000 + i, 1);

    for (int64_t i = 0; i < iters; i++)
      sum2 += pi_legendre(10000000 + i, 1);

    if (sum1 == sum2)
    {
      std::cout << "Multi-thread sum: " << sum1 << " == Single-thread sum: " << sum2 << "   OK" << std::endl;
      std::cout << "phi(x, a) multi-threading: no data races detected!" << std::endl;
    }
    else
    {
      std::cout << "Multi-thread sum: " << sum1 << " != Single-thread sum: " << sum2 << "   ERROR" << std::endl;
      std::exit(1);
    }
  }

  std::cout << std::endl;
  std::cout << "All tests passed successfully!" << std::endl;

  return 0;
}