-
-
Notifications
You must be signed in to change notification settings - Fork 220
Expand file tree
/
Copy pathpiWithInterrupts.cpp
More file actions
134 lines (114 loc) · 3.1 KB
/
piWithInterrupts.cpp
File metadata and controls
134 lines (114 loc) · 3.1 KB
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
// -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; tab-width: 8 -*-
#include <Rcpp.h>
#ifdef _OPENMP
#include <omp.h>
#endif
#include <R_ext/Utils.h>
/**
* Base class for interrupt exceptions thrown when user
* interrupts are detected.
*/
class interrupt_exception : public std::exception {
public:
/**
* Constructor.
* @param[in] message A description of event that
* caused this exception.
*/
interrupt_exception(std::string message)
: detailed_message(message)
{};
/**
* Virtual destructor. Needed to avoid "looser throw specification" errors.
*/
virtual ~interrupt_exception() throw() {};
/**
* Obtain a description of the exception.
* @return Description.
*/
virtual const char* what() const throw() {
return detailed_message.c_str();
}
/**
* String with details on the error.
*/
std::string detailed_message;
};
/**
* Do the actual check for an interrupt.
* @attention This method should never be called directly.
* @param[in] dummy Dummy argument.
*/
static inline void check_interrupt_impl(void* /*dummy*/) {
R_CheckUserInterrupt();
}
/**
* Call this method to check for user interrupts.
* This is based on the results of a discussion on the
* R-devel mailing list, suggested by Simon Urbanek.
* @attention This method must not be called by any other
* thread than the master thread. If called from within
* an OpenMP parallel for loop, make sure to check
* for omp_get_thread_num()==0 before calling this method!
* @return True, if a user interrupt has been detected.
*/
inline bool check_interrupt() {
return (R_ToplevelExec(check_interrupt_impl, NULL) == FALSE);
}
/**
* Compute pi using the Leibniz formula
* (a very inefficient approach).
* @param[in] n Number of summands
* @param[in] frequency Check for interrupts after
* every @p frequency loop cycles.
*/
RcppExport SEXP PiLeibniz(SEXP n, SEXP frequency)
{
BEGIN_RCPP
// cast parameters
int n_cycles = Rcpp::as<int>(n);
int interrupt_check_frequency = Rcpp::as<int>(frequency);
// user interrupt flag
bool interrupt = false;
double pi = 0;
#ifdef _OPENMP
#pragma omp parallel for \
shared(interrupt_check_frequency, n_cycles, interrupt) \
reduction(+:pi)
#endif
for (int i=0; i<n_cycles; i+=interrupt_check_frequency) {
// check for user interrupt
if (interrupt) {
continue;
}
#ifdef _OPENMP
if (omp_get_thread_num() == 0) // only in master thread!
#endif
if (check_interrupt()) {
interrupt = true;
}
// do actual computations
int j_end = std::min(i+interrupt_check_frequency, n_cycles);
for (int j=i; j<j_end; ++j) {
double summand = 1.0 / (double)(2*j + 1);
if (j % 2 == 0) {
pi += summand;
}
else {
pi -= summand;
}
}
}
// additional check, in case frequency was too large
if (check_interrupt()) {
interrupt = true;
}
// throw exception if interrupt occurred
if (interrupt) {
throw interrupt_exception("The computation of pi was interrupted.");
}
pi *= 4.0;
// result list
return Rcpp::wrap(pi);
END_RCPP
}