I am testing 2 ways of calculating Prod(b-a), where a and b are vectors of length n. Prod(b-a)=(b1-a1)(b2-a2)(b3-a3)*... (bn-an), where b_i>a_i>0 for all i=1,2,3, n. For some special cases, another way (Method 2) of calculation this prod(b-a) is more efficient. It uses the following formula, which is to expand the terms and sum them:
Here is my question is: When it happens that a_i very close to b_i, the true outcome could be very, very close 0, something like 10^(-16). Method 1 (substract and Multiply) always returns positive output. Method 2 of using the formula some times return negative output ( about 7~8% of time returning negative for my experiment). Mathematically, these 2 methods should return exactly the same output. But in computer language, it apparently produces different outputs.
Here are my codes to run the test. When I run the testing code for 10000 times, about 7~8% of my runs for method 2 returns negative output. According to the official document, the R double has the precision of "2.225074e-308" as indicated by R parameter: ".Machine$double.xmin". Why it's getting into the negative values when the differences are between 10^(-16) ~ 10^(-18)? Any help that sheds light on this will be apprecaited. I would also love some suggestions concerning how to practically increase the precision to higher level as indicated by R document.
##########  Testing code 1.  
ftest1case<-function(a,b)  {
  n<-length(a)
  if (length(b)!=n) stop("---------  length a and b are not right.")
  if ( any(b<a) ) stop("----------  b has to be greater than a all the time.")
  out1<-prod(b-a)
  
  out2<-0
  N<-2^n
  for ( i in 1:N ) {
    tidx<-rev(as.integer(intToBits(x=i-1))[1:n])
    tsign<-ifelse( (sum(tidx)%%2)==0,1.0,-1.0)
    out2<-out2+tsign*prod(b[tidx==0])*prod(a[tidx==1])
  }
  c(out1,out2)
}
##########  Testing code 2.  
ftestManyCases<-function(N,printFreq=1000,smallNum=10^(-20))
{
  tt<-matrix(0,nrow=N,ncol=2)
  n<-12
  for ( i in 1:N) {
    a<-runif(n,0,1)
    b<-a+runif(n,0,1)*0.1
    tt[i,]<-ftest1case(a=a,b=b)
  
    if ( (i%%printFreq)==0 ) cat("----- i = ",i,"\n")
    if ( tt[i,2]< smallNum ) cat("------ i = ",i, " ---- Negative summation found.\n")
  }
  
  tout<-apply(tt,2,FUN=function(x)  { round(sum(x<smallNum)/N,6) } )
  names(tout)<-c("PerLess0_Method1","PerLee0_Method2")
  list(summary=tout, data=tt)  
}  
 
########  Step 1.  Test for 1 case.
n<-12
a<-runif(n,0,1)
b<-a+runif(n,0,1)*0.1
ftest1case(a=a,b=b)   
########  Step 2   Test Code 2 for multiple cases.
N<-300
tt<-ftestManyCases(N=N,printFreq = 100) 
tt[[1]]

 
     
    
