Chapter 18 論理演算

18.1 LogicalVector の正体

C++ の論理値型は bool であるので、LogicalVector の要素の型も bool であると思うかもしれないが、実際には int 型です。(R でも論理ベクトルの実体は整数ベクトルである) なぜこのようになっているかというと bool で表現できるのは truefalse の2つだけですが、R の論理ベクトルの要素の値には TRUE, FALSE,NA の3つがあり得るためです。

Rcpp では TRUE は 1、FALSE は 0、NANA_LOGICAL(int の最小値)で表現されています。

logical Rcppの記号 int bool
TRUE TRUE 1 (0以外の値) true
FALSE FALSE 0 false
NA NA_LOGICAL int の最小値 true

18.2 論理演算

LogicalVector の要素ごとの論理演算には演算子 &(論理積) |(論理和) !(論理否定)を用います。

LogicalVector v1 = {1,1,0,0};
LogicalVector v2 = {1,0,1,0};

LogicalVector res1 = v1 & v2;
LogicalVector res2 = v1 | v2;
LogicalVector res3 = !(v1 | v2);

Rcout << res1 << "\n"; // 1 0 0 0
Rcout << res2 << "\n"; // 1 1 1 0
Rcout << res3 << "\n"; // 0 0 0 1

18.3 LogicalVector を受け取る関数

LogicalVector を受け取る関数には all() any() ifelse() があります。

18.3.1 all() と any()

LogicalVector v に対して、all(v) は、v の全ての要素が TRUE の時 TRUE を返します。any(v) は、v のいずれかのの要素が TRUE の時、TRUEを返します。

all() 関数や any() 関数の返値を if 文の条件式としてそのまま用いることはできません。これは all() 関数と any() 関数の返値の型は SingleLogicalResult という型になっているためです。all() 関数や any() 関数の返値を if 文の条件式として用いるためには関数 is_true() is_false() is_na() を使って返値を bool 型に変換します。

下のコード例では、関数 all()any() の返値を if 文の条件式として使うときの方法を示します。この例では、全ての if 文の条件式は真となります、そして、all(), any() の返値を表示します。

18.3.2 ifelse()

ifelse(v, x1, x2) は論理ベクター v を受け取り、v の要素が TRUE の時には x1 の対応する要素を, FALSE の時には x2 の対応する要素を返します。 x1, x2 はベクターでもスカラーでも良いですが、ベクターの場合にはその長さは v と一致している必要があります。

(注):Rf_mkChar() はC言語の文字列型 (char*) を CHARSXPCharacterVector の要素の型)に変換する関数です。

18.4 LogicalVector の要素の評価

LogicalVector の要素の値を、そのまま if 文の条件式として使用してはいけません。なぜなら、C++ の if 文の条件式は式の値をbool 型として評価するのですが、 bool 型は 0 以外の値を全て true と評価するので、LogicalVectorNANA_LOGICAL) は true と評価されてしまうためです。

LogicalVector の要素の値を if 文で評価する方法については、次のコード例を参考にしてください。

// [[Rcpp::export]]
LogicalVector rcpp_logical(){
  
  // NA を含む整数ベクトルを作成します
  IntegerVector x = {1,2,3,4,NA_INTEGER};
  
  // 比較演算の結果は LogicalVector となります
  LogicalVector v = (x >= 3); 
  
  // LogicalVector の要素を直接 if 文の条件式で使うと
  // NA_LOGICAL は TRUE と評価されてしまいます
  for(int i=0; i<v.size();++i) {
    if(v[i]) Rprintf("v[%i] is evaluated as true.\n",i);
    else Rprintf("v[%i] is evaluated as false.\n",i);
  } 
  
  // LogicalVector の要素の評価します
  for(int i=0; i<v.size();++i) {
    if(v[i]==TRUE) Rprintf("v[%i] is TRUE.\n",i);
    else if (v[i]==FALSE) Rprintf("v[%i] is FALSE.\n",i);
    else if (v[i]==NA_LOGICAL) Rprintf("v[%i] is NA.\n",i);
    else Rcout << "v[" << i << "] is not 1\n";
  }
  
  // TRUE FALSE NA_LOGICAL の値を表示します
  Rcout << "TRUE " << TRUE << "\n";
  Rcout << "FALSE " << FALSE << "\n";
  Rcout << "NA_LOGICAL " << NA_LOGICAL << "\n";
  
  return v;
}

実行結果

> rcpp_logical()
v[0] is evaluated as false.
v[1] is evaluated as false.
v[2] is evaluated as true.
v[3] is evaluated as true.
v[4] is evaluated as true.
v[0] is FALSE.
v[1] is FALSE.
v[2] is TRUE.
v[3] is TRUE.
v[4] is NA.
TRUE 1
FALSE 0
NA_LOGICAL -2147483648
[1] FALSE FALSE  TRUE  TRUE    NA

#R ライクな関数

R の関数と類似した Rcpp の関数の一覧を示します。

また、これらの関数に与えるベクトルに NA が含まれていないと保証できる場合には、noNA()を使って印をつけると Rcpp 関数が NA のチェックを行わなくなるので計算が速くなる場合があります。

NumericVector res = mean(noNA(v));