Suppose I have a vector of elements that I want to add:
a <- c(1,2,-7,5)
Here are some additional test cases:
a <- c(1,2,-3,5)
a <- c(1,2,-7,-3,5)
I know I can use sum(a)
to get the result, but what if I had a condition to watch out for:
current_sum = 0
for(i in 1:length(a)){
last_sum = current_sum
current_sum = current_sum + a[i]
if(current_sum < 0)
{
current_sum = last_sum
current_sum = current_sum + (a[i]*-1)
}
}
Here, each time the sum is negative, we go back to the previous sum and add the opposite of that number that made the sum go negative. Outputting 15 as a result of the first example
Obviously, the vector of elements is not known before hand and performance is of issue. Is there any fully vectorized method or a more efficient way to do this in general (avoiding loops) ?
I find the R/C interface very useful for the tasks in which performance is important, there isn't an obvious vectorized R solution and the code in C is very easy to write. Try this:
require(inline)
.internalSumPositive<-cfunction(sig=c(v="SEXP"), language="C", body="
double sum=0.0;
int i,n = length(v);
double *values = REAL(v);
SEXP ret = PROTECT(allocVector(REALSXP,1));
for (i=0;i<n;i++) {
sum += values[i];
if (sum<0) sum = sum - 2*values[i];
}
REAL(ret)[0] = sum;
UNPROTECT(1);
return ret;")
sumPositive<-function(v) {
if (!is.numeric(v)) stop("Argument must be numeric")
if (length(v)==0) return(numeric(0))
.internalSumPositive(as.numeric(v))
}
Then you can try:
sumPositive(c(1,2,-7,5))
#[1] 15
sumPositive(c(1,2,-3,5))
#[1] 5
sumPositive(c(1,2,-7,-3,5))
#[1] 12
I won't report benchmark since it's not even a contest with the other proposed R solutions (this can be tens of thousands times faster).
Try this
f1 <- function(x) repeat{pos<-min(which(cumsum(x)<0))
x[pos]<-abs(x[pos])
if(all(cumsum(x)>=0)){return(sum(x));break}}
a <- c(1,2,-7,-3,5)
f1(a)
#[1] 12
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With