Algorithms_in_C  1.0.0
Set of algorithms implemented in C.
sol2.c File Reference

Problem 23 solution - optimization using look-up array More...

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
Include dependency graph for sol2.c:

Functions

char get_perfect_number (unsigned long N)
 
char is_abundant (unsigned long N)
 
unsigned long get_next_abundant (unsigned long N)
 
char is_sum_of_abundant (unsigned long N)
 
int main (int argc, char **argv)
 

Variables

long MAX_N = 28123
 
char * abundant_flags = NULL
 

Detailed Description

Problem 23 solution - optimization using look-up array

Author
Krishna Vedala

Optimization applied - compute & store abundant numbers once into a look-up array.

Function Documentation

◆ get_next_abundant()

unsigned long get_next_abundant ( unsigned long  N)

Find the next abundant number after N and not including N

71 {
72  unsigned long i;
73  /* keep checking successive numbers till an abundant number is found */
74  for (i = N + 1; !is_abundant(i); ++i)
75  ;
76  return i;
77 }
Here is the call graph for this function:

◆ get_perfect_number()

char get_perfect_number ( unsigned long  N)
Returns
-1 if N is deficient
1 if N is abundant
0 if N is perfect
34 {
35  unsigned long sum = 1;
36  char ret = 0;
37 
38  for (unsigned long i = 2; i * i <= N; i++)
39  {
40  if (N % i == 0)
41  {
42  sum += i;
43  unsigned long tmp = N / i;
44  if (tmp != i)
45  sum += tmp;
46  }
47  }
48 
49  ret = sum == N ? 0 : (sum > N ? 1 : -1);
50 #ifdef DEBUG
51  printf("%5lu: %5lu : %d\n", N, sum, ret);
52 #endif
53  return ret;
54 }

◆ is_abundant()

char is_abundant ( unsigned long  N)

Is the given number an abundant number (1) or not (0)

60 {
61  // return abundant_flags[N >> 3] & (1 << N % 8) ? 1 : 0;
62  return abundant_flags[N >> 3] & (1 << (N & 7))
63  ? 1
64  : 0; /* optimized modulo operation */
65 }

◆ is_sum_of_abundant()

char is_sum_of_abundant ( unsigned long  N)

check if a given number can be represented as a sum of two abundant numbers.

Returns
1 - if yes
0 - if not

optimized logic: i + j = N where both i and j should be abundant hence we can simply check for j = N - i as we loop through i

86 {
87  /** optimized logic:
88  * i + j = N where both i and j should be abundant
89  * hence we can simply check for j = N - i as we loop through i
90  **/
91  for (unsigned long i = get_next_abundant(1); i <= (N >> 1);
92  i = get_next_abundant(i))
93  if (is_abundant(N - i))
94  {
95 #ifdef DEBUG
96  printf("\t%4lu + %4lu = %4lu\n", i, N - i, N);
97 #endif
98  return 1;
99  }
100  return 0;
101 }
Here is the call graph for this function:

◆ main()

int main ( int  argc,
char **  argv 
)

Main function

byte array to store flags to identify abundant numbers the flags are identified by bits

105 {
106  unsigned long sum = 0;
107  if (argc == 2)
108  MAX_N = strtoul(argv[1], NULL, 10);
109 
110  /** byte array to store flags to identify abundant numbers
111  * the flags are identified by bits
112  **/
113  abundant_flags = (char *)calloc(MAX_N >> 3, 1);
114  if (!abundant_flags)
115  {
116  perror("Unable to allocate memoey!");
117  return -1;
118  }
119 
120 #ifdef _OPENMP
121  printf("Using OpenMP parallleization with %d threads\n",
122  omp_get_max_threads());
123 #else
124  printf("Not using parallleization!\n");
125 #endif
126 
127  clock_t start_time = clock();
128 
129  /* Loop to set abundant flags */
130  long N;
131 #ifdef _OPENMP
132 #pragma omp for schedule(runtime)
133 #endif
134  for (N = 1; N <= MAX_N; N++)
135  {
136  char ret = get_perfect_number(N);
137  if (ret == 1)
138  {
139  // int byte_offset = N % 8, index = N >> 3;
140  int byte_offset = N & 7, index = N >> 3;
141 #ifdef _OPENMP
142 #pragma omp critical
143 #endif
144  abundant_flags[index] |= ret << byte_offset;
145  }
146  // if (i % 100 == 0)
147  // printf("... %5lu: %8lu\r", i, sum);
148  }
149 
150  clock_t end_time = clock();
151  double t1 = 1e3 * (end_time - start_time) / CLOCKS_PER_SEC;
152  printf("Time taken to get abundant numbers: %.4g ms\n", t1);
153 
154  clock_t t2 = 0;
155  long i;
156 #ifdef _OPENMP
157 #pragma omp parallel for schedule(runtime) reduction(+ : sum)
158 #endif
159  for (i = 1; i < MAX_N; i++)
160  {
161  clock_t start_time1 = clock();
162  if (!is_sum_of_abundant(i))
163  // #ifdef _OPENMP
164  // #pragma omp critical
165  // #endif
166  sum += i;
167  clock_t end_time1 = clock();
168 #ifdef _OPENMP
169 #pragma omp critical
170 #endif
171  t2 += end_time1 - start_time1;
172 
173  printf("... %5lu: %8lu\r", i, sum);
174  if (i % 100 == 0)
175  fflush(stdout);
176  }
177 
178 #ifdef DEBUG
179  putchar('\n');
180 #endif
181  double t22 = 1e3 * t2 / CLOCKS_PER_SEC;
182  printf("Time taken for final sum: %.4g ms\nTotal Time taken: %.4g ms\n",
183  t22, t1 + t22);
184  printf("Memory used: %lu bytes\n", MAX_N >> 3);
185  printf("Sum of numbers that cannot be represented as sum of two abundant "
186  "numbers : %lu\n",
187  sum);
188 
189  free(abundant_flags);
190 
191  return 0;
192 }
Here is the call graph for this function:

Variable Documentation

◆ abundant_flags

char* abundant_flags = NULL

This is the global array to be used to store a flag to identify if a particular number is abundant (1) or not (0). Using a whole byte to store a binary info would be redundant. We will use each byte to represent 8 numbers by relying on bits. This saves memory required by 1/8

◆ MAX_N

long MAX_N = 28123

Limit of numbers to check

get_perfect_number
char get_perfect_number(unsigned long N)
Definition: sol2.c:33
N
#define N
Definition: sol1.c:111
get_next_abundant
unsigned long get_next_abundant(unsigned long N)
Definition: sol2.c:70
is_abundant
char is_abundant(unsigned long N)
Definition: sol2.c:59
is_sum_of_abundant
char is_sum_of_abundant(unsigned long N)
Definition: sol2.c:85
MAX_N
long MAX_N
Definition: sol2.c:17
abundant_flags
char * abundant_flags
Definition: sol2.c:26