Template:ROOT/Exercises/A Simple Stand-Alone Application

Exercise edit

Once again, consider the code you should have previously written to compute the mean of an array of random numbers. Now, last but not least, make it a stand-alone application and run it independently of any ROOT session. Make sure that passing parameters will still work. Check the performance of your application. Take also care that your modifications don't disturb interpretation or on-the-fly compilation by CINT or ACLiC.

Solution edit

What we have to do is to add an int main() function. But this will bother CINT. So we hide it by putting a preprocessor command around it that will ignore it if the variable __CINT__ is defined.

# ifndef __CINT__  // the following code will be invisible for the interpreter

int main()
{
  random_mean();
}

# endif

This works. But it doesn't allow us to pass command line arguments yet. So to make it complete, we add a check if any parameters are given and if so, we convert the second (the first is—as always—the name of the application) to an integer and call random_mean with it. The conversation may be done with the strtof method that can be found in the cstdlib.

The final code should look like this:

// compile with:  g++ -o random_mean random_mean.cc `root-config --cflags --glibs`

# include <cstdlib>  // needed to convert string argument to integer
# include <iostream>
# include "TRandom.h"

using namespace std;

void random_mean(Int_t nums)
{
  TRandom *R = new TRandom(time(0));
  Double_t *seed = new Double_t[nums];
  for (Int_t i = 0; i < nums; i++)
  {
    seed[i] = R->Rndm();
  }
  Double_t mean = 0.0;
  for (Int_t i = 0; i < nums; i++)
  {
    mean += seed[i];
  }
  mean /= nums;
  cout << "mean = " << mean << endl;
}

void random_mean()
{
  random_mean(100000000); // on default, take 1E8 numbers
}

# ifndef __CINT__  // the following code will be invisible for the interpreter

int main(int argc, char **argv)
{
  if (argc == 1)  // no parameter given
  {
    random_mean();
  }
  else
  {
    Int_t parameter = (Int_t) strtof(argv[1], NULL);  // convert the second parameter to an integer
    random_mean(parameter);
  }
}

# endif

Now we can compile the code using an external compiler

g++ -o random_mean random_mean.cc `root-config --cflags --glibs`

and also execute it without starting ROOT. With or without a parameter. Check out how fast it is!

./random_mean 34
mean = 0.500596
./random_mean
mean = 0.500062

Note that is is still possible to interpret or compile your macro on-the-fly.

root [0] .x random_mean.cc(10)
mean = 0.568087
root [1] .x random_mean.cc+(10)
Info in <ACLiC>: script has already been loaded in interpreted mode
Info in <ACLiC>: unloading /home/tux/Desktop/test/./random_mean.cc and compiling it
mean = 0.535071

So after a long journey, we have finally made the ultimate ROOT source file. I also recommend this strategy when developing something new. First try it interactively. If you know what to do, start writing your macro and test it on the interpreter. If it is more or less finished, make sure the code is clean and test it on larger amounts of data as compiled code. And finally make it a stand.alone application (if needed). It is wonderful that ROOT supports all these possibilities.

One more thing to note: This was a basic example. To build a stand-alone application with a ROOT GUI a slightly more difficult setup is needed.