Rcpp Version 0.9.10
piWithInterrupts.cpp
Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerator Friends Defines