Та же функция Rcpp возвращает разные выходные данные, если добавлен оператор печати

#c #r #rcpp

#c #r #rcpp

Вопрос:

Функция C , которую я написал с использованием Rcpp, выдает разные выходные данные в зависимости от того, есть ли у меня оператор Rcout or Rprintf в коде. Приведенный ниже код возвращает 1 правильное значение для функции с оператором печати H_sigma_1() . Однако для H_sigma_2() функции без оператора печати функция возвращает 2. Я тестировал это на Ubuntu 16.04.1, а также CentOS 6.8. Хотя я не смог воспроизвести эту ошибку в Windows 10. Следовательно, это, похоже, проблема Linux.

Код Rcpp

 library(Rcpp)

cppFunction ( 
  "double H_sigma_1(IntegerVector sigma, NumericMatrix J, NumericVector h)
  {
    double first_sum, second_sum = 0;
    int n = sigma.size();

    for(int i = 0; i < n; i  )
    {
      for(int j = 0; j < n; j  )
      {
        // skip inside loop if i >= j to stop double counting
        if(i >= j) {continue;}
        first_sum  = J(i, j) * sigma[i] * sigma[j];
        Rcout << first_sum << std::endl;
      }
      second_sum  = h[i] * sigma[i];
    }
    return(-1.0 * first_sum - second_sum);
  }"
)

cppFunction (
  "double H_sigma_2(IntegerVector sigma, NumericMatrix J, NumericVector h)
  {
    double first_sum, second_sum = 0;
    int n = sigma.size();

    for(int i = 0; i < n; i  )
    {
      for(int j = 0; j < n; j  )
      {
        // skip inside loop if i >= j to stop double counting
        if(i >= j) {continue;}
        first_sum  = J(i, j) * sigma[i] * sigma[j];
        // Rcout << first_sum << std::endl;
      }
      second_sum  = h[i] * sigma[i];
    }
    return(-1.0 * first_sum - second_sum);
  }"
)
  

Пример вызова

Настройка:

 n = 2
params = rep(1, n) 
h = rep(params[1], n)
J = toeplitz(c(0, params[2], rep(0, n - 2)))
  

Тест 1:

 H_sigma_1(c(-1, -1), J, h)
  

Вывод:

 1
[1] 1
  

Тест 2

 H_sigma_2(c(-1, -1), J, h)
  

Вывод

 [1] 2
  

Ответ №1:

Проблема, с которой вы столкнулись, заключается в том, что начальные значения для сумм явно не объявляются перед их использованием.

 double first_sum, second_sum = 0;
  

не совпадает с:

 double first_sum = 0, second_sum = 0;
  

Смотрите Флаги предупреждения компилятора:

 file11d36f564b15.cpp:17:5: warning: variable 'first_sum' is uninitialized when used here [-Wuninitialized]
    first_sum  = J(i, j) * sigma[i] * sigma[j];
    ^~~~~~~~~
file11d36f564b15.cpp:8:21: note: initialize the variable 'first_sum' to silence this warning
    double first_sum, second_sum = 0;
  

Вы сразу же используете:

 first_sum  = J(i, j) * sigma[i] * sigma[j];
  

без установки first_sum = ...;


Кроме того, другая проблема заключается в:

 second_sum = 0;
  

инициализирует double целочисленным значением. Хотя эта проблема незначительна по объему, чтобы исправить это, все, что нужно сделать, это использовать 0.0 вместо 0 .

 second_sum = 0.0;
  

Это также относится к first_sum .


Код с вышеуказанными исправлениями:

 library(Rcpp)

cppFunction ( 
    "double H_sigma_1(IntegerVector sigma, NumericMatrix J, NumericVector h)
    {
    double first_sum = 0.0, second_sum = 0.0;
    int n = sigma.size();

    for(int i = 0; i < n; i  ) {
      for(int j = 0; j < n; j  ) {
        // skip inside loop if i >= j to stop double counting
        if(i >= j) {continue;}
        first_sum  = J(i, j) * sigma[i] * sigma[j];
        Rcout << first_sum << std::endl;
      }
      second_sum  = h[i] * sigma[i];
    }
    return(-1.0 * first_sum - second_sum);
    }"
)

cppFunction ( 
    "double H_sigma_2(IntegerVector sigma, NumericMatrix J, NumericVector h)
    {
    double first_sum = 0.0, second_sum = 0.0;
    int n = sigma.size();

    for(int i = 0; i < n; i  ) {
      for(int j = 0; j < n; j  ) {
        // skip inside loop if i >= j to stop double counting
        if(i >= j) {continue;}
        first_sum  = J(i, j) * sigma[i] * sigma[j];
      }
      second_sum  = h[i] * sigma[i];
    }
    return(-1.0 * first_sum - second_sum);
    }"
)
  

Тест:

 n = 2
params = rep(1, n) 
h = rep(params[1], n)
J = toeplitz(c(0, params[2], rep(0, n - 2)))

H_sigma_1(c(-1, -1), J, h)
  

Вывод:

 1
[1] 1
  

Тест 2:

 H_sigma_2(c(-1, -1), J, h)
  

Вывод:

 [1] 1