Skip to content
Snippets Groups Projects
Random.h 5.77 KiB
Newer Older
//======================================================================================================================
//
//  This file is part of waLBerla. waLBerla is free software: you can 
//  redistribute it and/or modify it under the terms of the GNU General Public
//  License as published by the Free Software Foundation, either version 3 of 
//  the License, or (at your option) any later version.
//  
//  waLBerla 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 General Public License 
//  for more details.
//  
//  You should have received a copy of the GNU General Public License along
//  with waLBerla (see COPYING.txt). If not, see <http://www.gnu.org/licenses/>.
//
//! \file Random.h
//! \ingroup core
//! \author Florian Schornbaum <florian.schornbaum@fau.de>
//
//======================================================================================================================

#pragma once

#include "core/DataTypes.h"
#include "core/debug/Debug.h"

#include <random>
#include <limits>


namespace walberla {
namespace math {



namespace internal {
std::mt19937 & getGenerator(); // std::mt19937_64
void seedRandomGenerator( const std::mt19937::result_type & seed ); // std::mt19937_64



//**********************************************************************************************************************
/*!
*   \brief Returns a random integral number of type INT in the range [min,max] (max included!)
*/
//**********************************************************************************************************************
template< typename INT >
INT intRandom( const INT min, const INT max, std::mt19937 & generator )
   static_assert(sizeof(INT) > sizeof(char), "cannot use char");
   std::uniform_int_distribution< INT > distribution( min, max );

   INT value;
#ifdef _OPENMP
   #pragma omp critical (random)
#endif
   { value = distribution( generator ); }

   return value;
}

template<>
inline char intRandom<char>( const char min, const char max, std::mt19937 & generator )
{
   static_assert_int_t< char >();
   WALBERLA_ASSERT_LESS_EQUAL( min, max );

   std::uniform_int_distribution< int16_t > distribution( min, max );

   char value;
#ifdef _OPENMP
   #pragma omp critical (random)
#endif
   { value = static_cast<char>( distribution( generator ) ); }

   return value;
}

template<>
inline unsigned char intRandom<unsigned char>( const unsigned char min, const unsigned char max, std::mt19937 & generator )
{
   static_assert_int_t< unsigned char >();
   WALBERLA_ASSERT_LESS_EQUAL( min, max );

   std::uniform_int_distribution< int16_t > distribution( min, max );

   unsigned char value;
#ifdef _OPENMP
   #pragma omp critical (random)
#endif
   { value = static_cast<unsigned char>( distribution( generator ) ); }

   return value;
}

template<>
inline signed char intRandom<signed char>( const signed char min, const signed char max, std::mt19937 & generator )
{
   static_assert_int_t< signed char >();
   WALBERLA_ASSERT_LESS_EQUAL( min, max );

   std::uniform_int_distribution< int16_t > distribution( min, max );

   signed char value;
#ifdef _OPENMP
   #pragma omp critical (random)
#endif
   { value = static_cast<signed char>( distribution( generator ) ); }

   return value;
}

template< typename INT >
INT intRandom( const INT min )
{
   return intRandom( min, std::numeric_limits<INT>::max(), internal::getGenerator() );
}

template< typename INT >
INT intRandom( const INT min, const INT max )
{
   return intRandom( min, max, internal::getGenerator() );
}

template< typename INT >
INT intRandom()
{
   return intRandom( std::numeric_limits<INT>::min(), std::numeric_limits<INT>::max() );
}


   IntRandom( const std::mt19937::result_type & seed = std::mt19937::result_type() ) { generator_.seed( seed ); }
   INT operator()( const INT min = std::numeric_limits<INT>::min(), const INT max = std::numeric_limits<INT>::max() )
   {
      return intRandom( min, max, generator_ );
   }
private:
   std::mt19937 generator_;
};



//**********************************************************************************************************************
/*!
*   \brief Returns a random floating point number of type REAL in the range [min,max) (max excluded!)
*/
//**********************************************************************************************************************
template< typename REAL >
REAL realRandom( const REAL min = REAL(0), const REAL max = REAL(1), std::mt19937 & generator = internal::getGenerator() )
{
   static_assert( std::numeric_limits<REAL>::is_specialized && !std::numeric_limits<REAL>::is_integer, "Floating point type required/expected!" );
   WALBERLA_ASSERT_LESS( min, max );

   std::uniform_real_distribution< REAL > distribution( min, max );

   REAL value;
#ifdef _OPENMP
   #pragma omp critical (random)
#endif
   { value = distribution( generator ); }

   return value;
}



template< typename REAL >
class RealRandom
{
public:
   RealRandom( const std::mt19937::result_type & seed = std::mt19937::result_type() ) { generator_.seed( seed ); }
   REAL operator()( const REAL min = REAL(0), const REAL max = REAL(1) )
   {
      return realRandom( min, max, generator_ );
   }
private:
   std::mt19937 generator_;
};



inline bool boolRandom() { ///< Randomly returns 'true' or 'false'
   return realRandom<real_t>() >= real_t(0.5);
}



class BoolRandom
{
public:
   BoolRandom( const std::mt19937::result_type & seed = std::mt19937::result_type() ) { generator_.seed( seed ); }
   bool operator()() { return boolRandom(); }
private:
   std::mt19937 generator_;