Chapter 11 Logical operations

11.1 LogicalVector

11.1.1 Data type of LogicalVector elements

Since boolean type in C++ is bool, you may think that the type of the element of LogicalVector is also bool, but it is int. This is because bool type can only represent true or false, but there are three possible values TRUE,FALSE, and NA for elements of the logical vector in R.

In Rcpp, TRUE is represented by 1,FALSE by 0, and NA byNA_LOGICAL (minimum value of int: -2147483648).

R Rcpp int bool
TRUE TRUE 1 (Values other than 0 and -2147483648) true
FALSE FALSE 0 false
NA NA_LOGICAL -2147483648 true

11.2 Logical operations

Use the operator & (logical product) | (logical sum) ! (Logical negation) for the logical operation for each element of 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

11.3 Function that receives LogicalVector

Examples of functions that receive LogicalVector are all(), any() and ifelse().

11.3.1 all(), any()

For LogicalVector v, all (v)returnsTRUE when all elements of v are TRUE, and any(v) returns TRUE if any of v’s elements are TRUE.

You can not use the return value of the all() and any() as the conditional expression of the if statement. This is because the return type of the all() and any() is not bool but SingleLogicalResult. To use the return value of the all() and any() as a conditional expression of an if statement, use the function is_true(), is_false() and is_na(). These functions convert SingleLogicalResult to bool.

The code example below shows how to use the return values of the functions all() and any() as a conditional expression of an if statement. In this example, the conditional expression of all if statements will be true, and the return value of all(), any() will be displayed.

// [[Rcpp::export]]
List rcpp_logical_03(){
  LogicalVector v1 = LogicalVector::create(1,1,1,NA_LOGICAL);
  LogicalVector v2 = LogicalVector::create(0,1,0,NA_LOGICAL);

  // Behavior of all (), any () for LogicalVector including NA is the same as R
  LogicalVector lv1 = all( v1 );   // NA
  LogicalVector lv2 = all( v2 );   // FALSE
  LogicalVector lv3 = any( v2 ); // TRUE

  // In case assigning to bool
  bool b1 = is_true ( all(v1) );  // false
  bool b2 = is_false( all(v1) );  // false
  bool b3 = is_na   ( all(v1) );  // true

  // In case used in conditional expression of if statement
  if(is_na(all( v1 ))) { // OK
    Rcout << "all( v1 ) is NA\n";
  }

  return List::create(lv1, lv2, lv3, b1, b2, b3);
}

11.3.2 ifelse()

ifelse (v, x1, x2) receives the logical vector v, and returns the corresponding element of x1 when the element of v is TRUE and the corresponding element of x2 when it isFALSE. Although x1 and x2 can be vectors or scalars, in the case of vectors the length of x1 and x2 must match the length of v.

NumericVector v1;
NumericVector v2;

//Number of elements of vector
int n = v1.length();

// In case, both x1 and x2 are scalar
IntegerVector res1     = ifelse( v1>v2, 1, 0);
NumericVector res2     = ifelse( v1>v2, 1.0, 0.0);
//CharacterVector res3 = ifelse( v1>v2, "T", "F"); // not supported


// Since ifelse() does not work with a scalar character string,
// in order to obtain results equivalent to R,
// we need to use a string vector whose values of elements are all the same.
CharacterVector chr_v1 = rep(CharacterVector("T"), n);
CharacterVector chr_v2 = rep(CharacterVector("F"), n);
CharacterVector res3   = ifelse( v1>v2, chr_v1, chr_v2);

// In case, x1 and x2 are vector and scalar
IntegerVector int_v1, int_v2;
NumericVector num_v1, num_v2;
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

// In case, x1 and x2 are vector and vector
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);

Note: Rf_mkChar () is a function that convert C language string (char*) to CHARSXP (type of element of CharacterVector).

11.4 Evaluation of elements of LogicalVector

The value of the element of LogicalVector should not be used as a conditional expression of if statement. Because the conditional expression of the C++ if statement evaluates the value of the expression as a bool type. bool type evaluates all values other than 0 as true, thus the NA of LogicalVector (NA_LOGICAL) is evaluated as true.

See the following code example for how to evaluate the value of an element of LogicalVector with an if statement.

// [[Rcpp::export]]
LogicalVector rcpp_logical(){

  // Create an integer vector containing NA
  IntegerVector x = {1,2,3,4,NA_INTEGER};

  // The result of the comparison operation becomes LogicalVector
  LogicalVector v = (x >= 3);

   // If you use the element of LogicalVector directly in the "if" statement
   // NA_LOGICAL will be evaluated as 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);
  }

  // Evaluate the elements of 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";
  }

  // Displays the value of TRUE, FALSE and NA_LOGICAL
  Rcout << "TRUE " << TRUE << "\n";
  Rcout << "FALSE " << FALSE << "\n";
  Rcout << "NA_LOGICAL " << NA_LOGICAL << "\n";

  return v;
}

Execution result

> 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