|
Rcpp Version 0.9.10
|
00001 // -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; tab-width: 8 -*- 00002 00003 #include <Rcpp.h> 00004 00005 #ifdef _OPENMP 00006 #include <omp.h> 00007 #endif 00008 00009 #include <R_ext/Utils.h> 00010 00015 class interrupt_exception : public std::exception { 00016 public: 00022 interrupt_exception(std::string message) 00023 : detailed_message(message) 00024 {}; 00025 00029 virtual ~interrupt_exception() throw() {}; 00030 00035 virtual const char* what() const throw() { 00036 return detailed_message.c_str(); 00037 } 00038 00042 std::string detailed_message; 00043 }; 00044 00050 static inline void check_interrupt_impl(void* /*dummy*/) { 00051 R_CheckUserInterrupt(); 00052 } 00053 00064 inline bool check_interrupt() { 00065 return (R_ToplevelExec(check_interrupt_impl, NULL) == FALSE); 00066 } 00067 00075 RcppExport SEXP PiLeibniz(SEXP n, SEXP frequency) 00076 { 00077 BEGIN_RCPP 00078 00079 // cast parameters 00080 int n_cycles = Rcpp::as<int>(n); 00081 int interrupt_check_frequency = Rcpp::as<int>(frequency); 00082 00083 // user interrupt flag 00084 bool interrupt = false; 00085 00086 double pi = 0; 00087 #ifdef _OPENMP 00088 #pragma omp parallel for \ 00089 shared(interrupt_check_frequency, n_cycles, interrupt) \ 00090 reduction(+:pi) 00091 #endif 00092 for (int i=0; i<n_cycles; i+=interrupt_check_frequency) { 00093 // check for user interrupt 00094 if (interrupt) { 00095 continue; 00096 } 00097 00098 #ifdef _OPENMP 00099 if (omp_get_thread_num() == 0) // only in master thread! 00100 #endif 00101 if (check_interrupt()) { 00102 interrupt = true; 00103 } 00104 00105 // do actual computations 00106 int j_end = std::min(i+interrupt_check_frequency, n_cycles); 00107 for (int j=i; j<j_end; ++j) { 00108 double summand = 1.0 / (double)(2*j + 1); 00109 if (j % 2 == 0) { 00110 pi += summand; 00111 } 00112 else { 00113 pi -= summand; 00114 } 00115 } 00116 } 00117 00118 // additional check, in case frequency was too large 00119 if (check_interrupt()) { 00120 interrupt = true; 00121 } 00122 00123 // throw exception if interrupt occurred 00124 if (interrupt) { 00125 throw interrupt_exception("The computation of pi was interrupted."); 00126 } 00127 00128 pi *= 4.0; 00129 00130 // result list 00131 return Rcpp::wrap(pi); 00132 00133 END_RCPP 00134 }