第 11 章 逻辑运算

11.1 LogicalVector

11.1.1 LogicalVector元素的数据类型

LogicalVector的元素类型不是bool。这是因为,bool只能表示truefalse,但是在R中,逻辑向量有三种可能的取值,即TRUEFALSE以及NA。因此,LogicalVector元素的数据类型为int,而非bool

在Rcpp中,TRUE用1表示,FALSE用0表示,而NANA_LOGICAL表示(整型的最小值:-2147483648)。

R Rcpp int bool
TRUE TRUE 1 (除却-2147483648至0之间的int) true
FALSE FALSE 0 false
NA NA_LOGICAL -2147483648 true

11.3 接收LogicalVector的函数

接收LogicalVector的函数有all(), any()ifelse()等。

11.3.1 all(), any()

对于LogicalVector v,当所有元素都为TRUE时,all (v)返回TRUE,当任意一个元素为TRUE时,any (v)返回TRUE

然而,用户并不能在if语句的条件表达式中,使用all()或者any()的返回值。这是因为这两者的返回值并不是bool型,而是SingleLogicalResult型。如果要在if条件语句中使用这两个函数,可以考虑使用is_true(), is_false()is_na()。这些函数会把SingleLogicalResult 类型转为bool型。

下面的代码展示了,如何在if语句的条件表达式中使用all()any()。在这个例子中,条件表达式的值为trueall()any()的返回值也会被打印显示。

test.cpp文件中输入下面代码。

在R中的运行结果为:

需要注意的是,在@ref(#LogicalVector-elements)中提到过,NA的值为-2147483648,与打印的lv1信息一致。

11.3.2 ifelse()

ifelse (v, x1, x2) 接收逻辑向量v,如果v中的某元素为TRUE,那么返回x1中对应位置的元素,如果为FLASE,那么返回x2中对应位置的元素。尽管x1x2可以是标量或者向量,但如果是向量,两者的长度必须与v的长度一致。

// [[Rcpp::export]]
int rcpp_logical_02(NumericVector v1, NumericVector v2){
  
  //向量元素个数
  int n = v1.length();
  // 情况1:x1 和 x2是标量的情况
  IntegerVector res1     = ifelse( v1>v2, 1, 0);
  NumericVector res2     = ifelse( v1>v2, 1.0, 0.0);
  
  //CharacterVector res3 = ifelse( v1>v2, "T", "F"); // 不支持此种写法
  //ifelse() 不支持字符串标量,为了得到和R一样的结果
  // 我们需要使用字符串向量,该向量所有元素相同 
  CharacterVector chr_v1 = rep(CharacterVector("T"), n);
  CharacterVector chr_v2 = rep(CharacterVector("F"), n);
  CharacterVector res3   = ifelse( v1>v2, chr_v1, chr_v2);
  Rcout <<"case1: both x1 and x2 are scalar"<<'\n';
  Rcout << "\t v1 > v2 " << res1 <<'\n';
  Rcout << "\t v1 > v2 " << res2 <<'\n';
  Rcout << "\t v1 > v2 " << res3 <<'\n';
  
  //情况2,x1是向量,x2是标量
  IntegerVector int_v1, int_v2;
  int_v1 = rep(1,n);
  int_v2 = rep(0,n);
  NumericVector num_v1, num_v2;
  num_v1 = rep(1.,n);
  num_v2 = rep(0.,n);
  
  IntegerVector   res4 = ifelse( v1>v2, int_v1, 0);
  NumericVector   res5 = ifelse( v1>v2, num_v1, 0.0);
  CharacterVector res6 = ifelse( v1>v2, chr_v1, Rf_mkChar("F")); // Note
  
  Rcout <<"case2: x1 and x2 are vector and scalar"<<'\n';
  Rcout << "\t v1 > v2 " << res4 <<'\n';
  Rcout << "\t v1 > v2 " << res5 <<'\n';
  Rcout << "\t v1 > v2 " << res6 <<'\n';
  
  //情况3,x1和x2均为向量
  IntegerVector   res7 = ifelse( v1>v2, int_v1, int_v2);
  NumericVector   res8 = ifelse( v1>v2, num_v1, num_v2);
  CharacterVector res9 = ifelse( v1>v2, chr_v1, chr_v2);
  
  Rcout <<"case3: both x1 and x2 are vector"<<'\n';
  Rcout << "\t v1 > v2 " << res7 <<'\n';
  Rcout << "\t v1 > v2 " << res8 <<'\n';
  Rcout << "\t v1 > v2 " << res9 <<'\n';
  
  return 0;
}

Note: Rf_mkChar ()函数作用为将C语言中的字符串(char*)转为CHARSXP(CharacterVector中的元素类型)。

在R中运行结果为:

11.4 LogicalVector元素的估值

LogicalVector的元素值不应当被用作if语句的条件表达式。因为,C++中if语句将条件表达式评估为bool型。而bool型把所有非零的值均评估为true,因此,LogicalVector中的NA(NA_LOGICAL)也会被认为是true

下面的代码示例展示了if语句是如何评估LogicalVector的元素值。

需要注意的是,在原始代码上,需要加入// [[Rcpp::plugins(cpp11)]]语句启动C++11的特性,否则代码会因为初始化语句而报错。

执行结果为: