Background

The master/slave framework has a facility for generating pseudo-random numbers that is meant to be independent of whether it is called on a master or a slave. However, it is possible to use it in such a way that the random number sequences get out of sync for brief periods. This note describes its behavior and makes suggestions about how to avoid such errors. Please note that the framework will also detect such errors and print an error message to the console if they occur.

The following relevant data are transmitted from the master to the slaves on each frame:

  1. The current value of the random number seed. (_randomSeed)
  2. A flag indicating whether or not the seed has been set by the user. (_randSeedSet)
  3. The number of calls to the random number generator since the last data exchange. (_numRandCalls)
  4. The number generated by the last such call. (_lastRandVal)

    The slaves compare the transmitted values to their own using the following code:
      _randSynchError = 0;
      if (!_firstTransfer) {
        if (lastNumCalls != _numRandCalls)
          _randSynchError |= 1;
        if ((lastSeed != _randomSeed)&&(!_randSeedSet))
          _randSynchError |= 2;
        if (tempRandVal != _lastRandVal)
          _randSynchError |= 4;
      } else
        _firstTransfer = 0;
      _numRandCalls = 0;
    

    The next call to the random number generator checks _randSynchError and prints one or more error messages based on its value.

Functions

void arMasterSlaveFramework::setRandomSeed( const long newSeed )

Sets the random seed on the master. The change takes effect only just before the next data transfer, so don't start generating random numbers too early, like in the framework's init() callback. A value of 0 for the seed is illegal and will be converted to -1 with a printed warning.

bool arMasterSlaveFramework::randUniformFloat( float& value )

Generates a new pseudo-random number using the ran1 algorithm from Numerical Recipes in C. Values are uniformly distributed in the unit interval, excluding 0 and 1 themselves. It returns a bool indicating if _randSynchError is 0. As side-effects, it (1) resets _randSynchError to 0, so there is at most one error message per frame; (2) modifies the seed; (3) increments a counter, which is reset to 0 after each master/slave data transfer.

Getting into trouble

The random number sequences will become desynchronized under these conditions, and possibly others (mind you, the framework will tell you that you've gotten into trouble):