modules/up/src/Core/gnu/RNG.cc

/* [<][>]
[^][v][top][bottom][index][help] */

FUNCTIONS

This source file includes following functions.
  1. RNG
  2. asFloat
  3. asDouble

// This may look like C code, but it is really -*- C++ -*-
/* 
Copyright (C) 1989 Free Software Foundation

This file is part of the GNU C++ Library.  This library is free
software; you can redistribute it and/or modify it under the terms of
the GNU Library General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your
option) any later version.  This library is distributed in the hope
that it will be useful, but WITHOUT ANY WARRANTY; without even the
implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE.  See the GNU Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free Software
Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifdef __GNUG__
#pragma implementation
#endif
#include <assert.h>
#include "gnu/builtin.h"
#include "gnu/RNG.h"

// These two static fields get initialized by RNG::RNG().
PrivateRNGSingleType RNG::singleMantissa;
PrivateRNGDoubleType RNG::doubleMantissa;

//
//      The scale constant is 2^-31. It is used to scale a 31 bit
//      long to a double.
//

//static const double randomDoubleScaleConstant = 4.656612873077392578125e-10;
//static const float  randomFloatScaleConstant = 4.656612873077392578125e-10;

static char initialized = 0;

RNG::RNG()
/* [<][>][^][v][top][bottom][index][help] */
{
  if (!initialized)
  {

        assert (sizeof(double) == 2 * sizeof(_G_uint32_t)); 

        //
        //      The following is a hack that I attribute to
        //      Andres Nowatzyk at CMU. The intent of the loop
        //      is to form the smallest number 0 <= x < 1.0,
        //      which is then used as a mask for two longwords.
        //      this gives us a fast way way to produce double
        //      precision numbers from longwords.
        //
        //      I know that this works for IEEE and VAX floating
        //      point representations.
        //
        //      A further complication is that gnu C will blow
        //      the following loop, unless compiled with -ffloat-store,
        //      because it uses extended representations for some of
        //      of the comparisons. Thus, we have the following hack.
        //      If we could specify #pragma optimize, we wouldn't need this.
        //

        PrivateRNGDoubleType t;
        PrivateRNGSingleType s;

#if _IEEE == 1
        
        t.d = 1.5;
        if ( t.u[1] == 0 ) {            // sun word order?
            t.u[0] = 0x3fffffff;
            t.u[1] = 0xffffffff;
        }
        else {
            t.u[0] = 0xffffffff;        // encore word order?
            t.u[1] = 0x3fffffff;
        }

        s.u = 0x3fffffff;
#else
        volatile double x = 1.0; // volatile needed when fp hardware used,
                             // and has greater precision than memory doubles
        double y = 0.5;
        do {                        // find largest fp-number < 2.0
            t.d = x;
            x += y;
            y *= 0.5;
        } while (x != t.d && x < 2.0);

        volatile float xx = 1.0; // volatile needed when fp hardware used,
                             // and has greater precision than memory floats
        float yy = 0.5;
        do {                        // find largest fp-number < 2.0
            s.s = xx;
            xx += yy;
            yy *= 0.5;
        } while (xx != s.s && xx < 2.0);
#endif
        // set doubleMantissa to 1 for each doubleMantissa bit
        doubleMantissa.d = 1.0;
        doubleMantissa.u[0] ^= t.u[0];
        doubleMantissa.u[1] ^= t.u[1];

        // set singleMantissa to 1 for each singleMantissa bit
        singleMantissa.s = 1.0;
        singleMantissa.u ^= s.u;

        initialized = 1;
    }
}

float RNG::asFloat()
/* [<][>][^][v][top][bottom][index][help] */
{
    PrivateRNGSingleType result;
    result.s = 1.0;
    result.u |= (asLong() & singleMantissa.u);
    result.s -= 1.0;
    assert( result.s < 1.0 && result.s >= 0);
    return( result.s );
}
        
double RNG::asDouble()
/* [<][>][^][v][top][bottom][index][help] */
{
    PrivateRNGDoubleType result;
    result.d = 1.0;
    result.u[0] |= (asLong() & doubleMantissa.u[0]);
    result.u[1] |= (asLong() & doubleMantissa.u[1]);
    result.d -= 1.0;
    assert( result.d < 1.0 && result.d >= 0);
    return( result.d );
}


/* [<][>][^][v][top][bottom][index][help] */