0

Every time I execute cal() function with the same parameter I get different output. Function g() always calculate the same result for same input. Are threads overwriting any variable?

void cal(uint_fast64_t n) {
    Bint num = N(n);
    Bint total = 0, i, max_size(__UINT64_MAX__);
    for(i = 1; i <= num; i+= max_size){
        #pragma omp parallel shared(i,num,total)  
        { 
            int id = omp_get_thread_num();
            int numthreads = omp_get_num_threads();
            Bint sum(0), k;
            for(uint64_t j = id; (j < __UINT64_MAX__); j+=numthreads){
                k = i+j;
                if(k > num){
                    i = k;
                    break;
                }
                sum = sum + g(k);
            }
            #pragma omp critical
                total += sum;
        }
    }
    std::cout << total << std::endl;
}
4
  • 3
    Can you tell us what Bint is? Commented Sep 3, 2019 at 14:36
  • 2
    for(uint64_t j = id; (j < __UINT64_MAX__); j+=numthreads){ probably does not do what you want. The loop conditions is always true unless j == __UINT64_MAX__, which is impossible for e.g. even id and numthreads. But you have UB regardless so this is only secondary. Commented Sep 3, 2019 at 15:02
  • Its BigInt object to hold large numbers (>2^64). I am using this library. Commented Sep 3, 2019 at 15:12
  • Actually I am trying to solve this this problem programmatically. I computed H(10) but to solve H(10^9) uint64_t is also not sufficient.That's why I am using BigInt. Commented Sep 3, 2019 at 15:19

2 Answers 2

7
if(k > num){
    i = k;
    break;
}

Here you modify the shared variable i (possibly multiple times in parallel) while other threads may be reading from it (for k = i+j), all without synchronization. This is a race condition and your code thus has Undefined Behavior.

Sign up to request clarification or add additional context in comments.

3 Comments

This is my single thread function: void cal_single_thread(uint_fast64_t n) { Bint num = N(n); Bint sum = 0, i = 0; for(i = 1; i <= num; ++i){ sum += g(i); } std::cout << sum << std::endl; } How can i modify it for openmp ?
@AjitJadhav There are several different ways, but comments are not the appropriate place to show those. In any case, I very much doubt that you will ever reach i >= __UINT64_MAX__. Do you know how large 2^64 is? 2^64 nanoseconds (~= CPU cycles) take 600 years.
Haha :).. you are right, I have to think in a different way to solve that! Anyway, due to that problem, I learned many things. Thank you all. I was surprised by the quick replies.
3

The value of j depends on the value of id. If different threads are used to do the math, you'll get different results.

        int id = omp_get_thread_num();      // <---
        int numthreads = omp_get_num_threads();
        Bint sum(0), k;
        for(uint64_t j = id; (j < __UINT64_MAX__); j+=numthreads){  // <---
            k = i+j;
            if(k > num){
                i = k;      // <---
                break;
            }
            sum = sum + g(k);

Further, you change i to k when k > num. This can happen much sooner or much later depending on which thread is picked up first to run the inner loop.

You may want to look at this question and answer.

Does an OpenMP ordered for always assign parts of the loop to threads in order, too?

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.