首页 > 解决方案 > 错误:使用 arma::dot 时未定义对“sdot_”的引用

问题描述

我使用 Rcpp::sourceCpp("test.cpp") 并输出以下错误信息。请注意, check1() 有效,而 check2 失败。区别在于“arma::vec”和“arma::fvec”。当我在 Windows 上尝试时发生错误。当我在linux上尝试它时,它可以工作。

(编辑:我在 Linux 上添加了我的 R 环境。PS:Linux 上的结果表明 float 比 double 快,这就是我更喜欢使用 float 的原因)

C:/RBuildTools/3.5/mingw_64/bin/g++  -std=gnu++11 -I"C:/PROGRA~1/R/R-36~1.1/include" -DNDEBUG -I../inst/include -fopenmp  -I"C:/Users/wenji/OneDrive/Documents/R/win-library/3.6/Rcpp/include" -I"C:/Users/wenji/OneDrive/Documents/R/win-library/3.6/RcppArmadillo/include" -I"Y:/"        -O2 -Wall  -mtune=generic -c check.cpp -o check.o
C:/RBuildTools/3.5/mingw_64/bin/g++ -shared -s -static-libgcc -o sourceCpp_3.dll tmp.def check.o -fopenmp -LC:/PROGRA~1/R/R-36~1.1/bin/x64 -lRlapack -LC:/PROGRA~1/R/R-36~1.1/bin/x64 -lRblas -lgfortran -lm -lquadmath -LC:/PROGRA~1/R/R-36~1.1/bin/x64 -lR
check.o:check.cpp:(.text+0xa18): undefined reference to `sdot_'
collect2.exe: error: ld returned 1 exit status

下面是Windows上的R环境

R version 3.6.1 (2019-07-05)
Platform: x86_64-w64-mingw32/x64 (64-bit)
Running under: Windows 10 x64 (build 18362)

Matrix products: default

Random number generation:
 RNG:     Mersenne-Twister 
 Normal:  Inversion 
 Sample:  Rounding 

locale:
[1] LC_COLLATE=English_United States.1252  LC_CTYPE=English_United States.1252   
[3] LC_MONETARY=English_United States.1252 LC_NUMERIC=C                          
[5] LC_TIME=English_United States.1252    

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

loaded via a namespace (and not attached):
[1] compiler_3.6.1            tools_3.6.1               RcppArmadillo_0.9.850.1.0
[4] Rcpp_1.0.3 

下面是Linux上的R环境

R version 3.6.3 (2020-02-29)
Platform: x86_64-pc-linux-gnu (64-bit)
Running under: Ubuntu 16.04.6 LTS

Matrix products: default
BLAS:   /usr/lib/openblas-base/libblas.so.3
LAPACK: /usr/lib/libopenblasp-r0.2.18.so

locale:
 [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C              
 [3] LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8    
 [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8   
 [7] LC_PAPER=en_US.UTF-8       LC_NAME=C                 
 [9] LC_ADDRESS=C               LC_TELEPHONE=C            
[11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C       

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

loaded via a namespace (and not attached):
[1] compiler_3.6.3            tools_3.6.3              
[3] RcppArmadillo_0.9.850.1.0 Rcpp_1.0.4  

以下是“test.cpp”的代码

// [[Rcpp::depends(RcppArmadillo)]]
#include <RcppArmadillo.h>

using namespace Rcpp;

// [[Rcpp::export]]
NumericVector timesTwo(NumericVector x) {
  return x * 2;
}

// [[Rcpp::export]]
arma::vec check1(arma::vec x1, arma::vec x2, int rep){
  int n = x1.size();
  arma::vec y(n);
  y.fill(0);
  for(int i = 0; i < rep; i ++){
    y += x1 * arma::dot(x1, x2);
  }
  return y;
}

// [[Rcpp::export]]
arma::fvec check2(arma::fvec x1, arma::fvec x2, int rep){
  int n = x1.size();
  arma::fvec y(n);
  y.fill(0);
  for(int i = 0; i < rep; i ++){
    y += x1 * arma::dot(x1, x2);
  }
  return y;
}

// You can include R code blocks in C++ files processed with sourceCpp
// (useful for testing and development). The R code will be automatically 
// run after the compilation.
//

/*** R
timesTwo(42)
n = 100000
x1 = rnorm(n)
x2 = rnorm(n)
rep = 1000
system.time(y1 <- check1(x1, x2, rep))
system.time(y2 <- check2(x1, x2, rep))
head(y1)
head(y2)
*/

以下是 Linux 上的输出

> system.time(y1 <- check1(x1, x2, rep))
   user  system elapsed 
  0.156   0.000   0.160 

> system.time(y2 <- check2(x1, x2, rep))
   user  system elapsed 
  0.088   0.000   0.100

标签: rrcpprcpparmadillo

解决方案


这里有两个问题:

  1. 为什么它适用于 Linux 而不是 Windows?

R 只有intand double,但没有float(或 64-bit integer)。在 Windows 上,您可能正在链接 R 自己的内部 LAPACK,它可能只有double. 在 Linux 上float可能存在系统 LAPACK。这是我最好的猜测。

  1. 你可以/你应该在犰狳上使用浮点数吗?

并不真地。R 仅具有double且没有float来回获取值将始终涉及副本并且效率较低。我会坚持下去double


推荐阅读