1// RUN: %libomp-cxx-compile -fopenmp-version=60 && %libomp-run
2#include <stdio.h>
3#include <omp.h>
4#include <limits.h>
5#include <complex.h>
6#include <math.h>
7#include "omp_testsuite.h"
8
9#define N 10
10class Sum {
11 int val;
12
13public:
14 Sum(int v = 0) : val(v) {}
15 Sum operator+(const Sum &rhs) const { return Sum(val + rhs.val); }
16 Sum &operator+=(const Sum &rhs) {
17 val += rhs.val;
18 return *this;
19 }
20 int getValue() const { return val; }
21};
22
23// Declare OpenMP reduction
24#pragma omp declare reduction(sum_reduction:Sum : omp_out += omp_in) \
25 initializer(omp_priv = Sum(0))
26
27#pragma omp declare reduction(sum_pctor_reduction:Sum : omp_out += omp_in) \
28 initializer(omp_priv = Sum(1)) // non-default ctor
29
30int checkUserDefinedReduction() {
31 Sum final_result_udr(0);
32 Sum final_result_udr_pctor(1);
33 Sum array_sum[N];
34 int error_flag = 0;
35 int expected_value = 0;
36 int expected_value_pctor = 0;
37 for (int i = 0; i < N; ++i) {
38 array_sum[i] = Sum(i);
39 expected_value += i; // Calculate expected sum: 0 + 1 + ... + (N-1)
40 expected_value_pctor += i;
41 }
42 int num_threads_for_pctor_calc = 4; // num_threads(4)
43 int priv_initializer_val_pctor = 1; // initializer(omp_priv = Sum(1))
44 expected_value_pctor +=
45 num_threads_for_pctor_calc + priv_initializer_val_pctor;
46#pragma omp parallel num_threads(4) private(final_result_udr) private( \
47 final_result_udr_pctor)
48 {
49#pragma omp for reduction(sum_reduction : final_result_udr) \
50 reduction(sum_pctor_reduction : final_result_udr_pctor)
51 for (int i = 0; i < N; ++i) {
52 final_result_udr += array_sum[i];
53 final_result_udr_pctor += array_sum[i];
54 }
55
56 if (final_result_udr.getValue() != expected_value ||
57 final_result_udr_pctor.getValue() != expected_value_pctor)
58 error_flag += 1;
59 }
60 return error_flag;
61}
62void performMinMaxRed(int &min_val, int &max_val) {
63 int input_data[] = {7, 3, 12, 5, 8};
64 int n_size = sizeof(input_data) / sizeof(input_data[0]);
65 min_val = INT_MAX;
66 max_val = INT_MIN;
67#pragma omp for reduction(original(private), min : min_val) \
68 reduction(original(private), max : max_val)
69 for (int i = 0; i < n_size; ++i) {
70 if (input_data[i] < min_val)
71 min_val = input_data[i];
72 if (input_data[i] > max_val)
73 max_val = input_data[i];
74 }
75}
76std::complex<double> doComplexReduction(std::complex<double> *arr) {
77 std::complex<double> result(1, 0);
78
79#pragma omp declare reduction(* : std::complex<double> : omp_out *= omp_in) \
80 initializer(omp_priv = std::complex<double>(1, 0))
81
82#pragma omp for reduction(original(private), * : result)
83 for (int i = 0; i < N; ++i)
84 result *= arr[i];
85
86 return result;
87}
88
89void performReductions(int n_elements, const int *input_values,
90 int &sum_val_out, int &prod_val_out,
91 float &float_sum_val_out) {
92 // private variables for this thread's reduction.
93 sum_val_out = 0;
94 prod_val_out = 1;
95 float_sum_val_out = 0.0f;
96
97 const float kPiValue = 3.14f;
98#pragma omp for reduction(original(private), + : sum_val_out) \
99 reduction(original(private), * : prod_val_out) \
100 reduction(original(private), + : float_sum_val_out)
101 for (int i = 0; i < n_elements; ++i) {
102 sum_val_out += input_values[i];
103 prod_val_out *= (i + 1);
104 float_sum_val_out += kPiValue;
105 }
106}
107int main(void) {
108 int input_array[N];
109 int total_errors = 0;
110 const float kPiVal = 3.14f;
111 const int kExpectedSum = 45; // Sum of 0..9
112 const int kExpectedProd = 3628800; // 10!
113 const float kExpectedFsum = 31.400000f; // 3.14f * 10
114 const float kTolerance = 1e-4f;
115 const int kExpectedMin = 3;
116 const int kExpectedMax = 12;
117 std::complex<double> arr[N];
118 std::complex<double> kExpectedComplex(1, 0);
119 // Initialize the array
120 for (int i = 1; i <= N; ++i) {
121 arr[i - 1] = std::complex<double>(
122 1.0 + 0.1 * i, 0.5 * i); // Avoid zero to prevent multiplication by zero
123 kExpectedComplex *= arr[i - 1];
124 }
125
126 for (int i = 0; i < N; i++)
127 input_array[i] = i;
128#pragma omp parallel num_threads(4)
129 {
130
131 int t_sum_v;
132 int t_prod_v;
133 float t_fsum_v;
134 performReductions(N, input_values: input_array, sum_val_out&: t_sum_v, prod_val_out&: t_prod_v, float_sum_val_out&: t_fsum_v);
135 if (t_sum_v != kExpectedSum)
136 total_errors++;
137 if (t_prod_v != kExpectedProd)
138 total_errors++;
139 if (std::abs(x: t_fsum_v - kExpectedFsum) > kTolerance)
140 total_errors++;
141 }
142#pragma omp parallel num_threads(4)
143 {
144 int t_min_v;
145 int t_max_v;
146 performMinMaxRed(min_val&: t_min_v, max_val&: t_max_v);
147 if (t_min_v != kExpectedMin)
148 total_errors++;
149 if (t_max_v != kExpectedMax)
150 total_errors++;
151 }
152 total_errors += checkUserDefinedReduction();
153#pragma omp parallel num_threads(4)
154 {
155 std::complex<double> result(1, 0);
156 result = doComplexReduction(arr);
157 if (std::abs(x: result.real() - kExpectedComplex.real()) > 1e-6 ||
158 std::abs(x: result.imag() - kExpectedComplex.imag()) > 1e-6) {
159 total_errors++;
160 }
161 }
162 if (total_errors != 0)
163 fprintf(stderr, format: "ERROR: reduction on private variable %d\n", total_errors);
164
165 return total_errors;
166}
167

source code of openmp/runtime/test/worksharing/for/omp_for_private_reduction.cpp