4

Given two values x and b, I want a function to clamp x to fall within [-b, b]. In particular:

  • If x is less than or equal to -b, then the function returns -b;
  • If x is greater than -b and less than b, then the function returns x;
  • If x is greater than or equal to b, then the function returns b.

In R I wrote the following function truncfn. Only part of this function works. Where did I make mistake? Is there an easier way to do this?

b <- 5

truncfn <- function(x){
  if((x<(-b))||(x==-b)) -b 
  if((x>(-b))&&(x<b)) x 
  if((x>b)||(x==b)) b
}

truncfn(10)
5
truncfn(4)
truncfn(-10)
TylerH
  • 20,799
  • 66
  • 75
  • 101
LaTeXFan
  • 1,136
  • 4
  • 14
  • 36

2 Answers2

11

I would use the pmin and pmax functions to do this is a single expression without if statements:

b <- 5
x <- seq(-10, 10)
pmax(pmin(x, b), -b)
# [1] -5 -5 -5 -5 -5 -5 -4 -3 -2 -1  0  1  2  3  4  5  5  5  5  5  5

You could have fixed your function by replacing the second and third if statements with else if statements (or alternately using return(b), return(x) and return(-b)). Here is a working version (I've taken the liberty to use <= instead of separately checking with < and ==):

truncfn <- function(x){
  if (x <= -b) -b
  else if (x > -b && x < b) x 
  else b
}
truncfn(10)
# [1] 5
truncfn(4)
# [1] 4
truncfn(-10)
# [1] -5

However note that the function I wrote with pmin and pmax can take a whole vector as input, while yours is limited to taking a single number.

josliber
  • 43,891
  • 12
  • 98
  • 133
3

You can use raster::clamp

library(raster)
b <- 5
v <- -10:10
raster::clamp(v, -b, b)
# [1] -5 -5 -5 -5 -5 -5 -4 -3 -2 -1  0  1  2  3  4  5  5  5  5  5  5
Robert Hijmans
  • 40,301
  • 4
  • 55
  • 63