Search code examples
floating-pointmsp430contiki

Strange logf behavior when calculating Poisson packet generation times in Contiki OS


I aim to generate packets accoding to Poisson distribution in Contiki Cooja using MSP430 Experimenter board (Exp430) platform (same issue applies to Zolertia Z1 motes which also have MSP430-based MCU). I included the math library and coded the Poisson distribution as:

float nextTime = (-2.000) * logf((rand() / (float)RANDOM_RAND_MAX));

where the actual formula behind the code is -a*ln(rand) in which rand must be a floating point number between 0 and 1. I created a simulation and tested the generated nextTime's and I realized that it generated 0.000 quite often. Then I broke the code into small pieces to see what values are causing 0.000 to be generated as:

float inner1 =(float)( (rand() / (float)RANDOM_RAND_MAX));

float inner2 = logf(inner1);

float nextTime =  (float) (-2.000)*inner2;

One of value of inner1 causing nextTime to be calculated as 0.000 was 0.135. Then I set inner1 to 0.135 and reloaded the simulation and what I got was inner2 as -2.2 and nextTime as 4.5 as it should be. This confused me, because when I set the inner2 to a constant value, nextTime is calculated correctly. But exactly this value was causing nextTime to be 0.000 previously. I'm just really curious about it, why it happens in this way. Btw, I know printing floats in Contiki is not supported and I used two different solutions to print these float values correctly(How to print floating point value using putchar? and https://sourceforge.net/p/contiki/mailman/message/25936733/) .


Solution

  • I'm surprised you can use rand().
    In contiki, for generate rand number you need to use random_rand()
    And include : #include "lib/random.h"

    Edit : For more explanation : The code of random_rand() :

    unsigned short
    random_rand(void)
    {
    /* In gcc int rand() uses RAND_MAX and long random() uses RANDOM_MAX=0x7FFFFFFF */
    /* RAND_MAX varies depending on the architecture */
    
      return (unsigned short)rand();
    }
    

    So it return unsigned short, whatever happen. If the RAND_MAX is not well defined, you'll have an overflow, giving you a signed number. Casting into unsigned do the trick.