// file: $isip/class/math/scalar/MScalar/mscl_00.cc
// version: $Id: mscl_00.cc 10636 2007-01-26 22:18:09Z tm334 $
//

// this file contains those methods that are not inlined in the MScalar
// template, but yet, not sufficiently complicated to be placed in
// MScalarMethods.h. The functions implemented here must be in the same
// file, due to the intricacies of template support in C++.
//

// isip include files
//
#include "MScalar.h"
#include <Error.h>

//-----------------------------------------------------------------------------
//
// miscellaneous methods
//      
//-----------------------------------------------------------------------------

// method: debug
//
// arguments:
//  const unichar* msg: (input) message to print
//
// return: a boolean value indicating status
//
template<class TIntegral, class TSize>
boolean MScalar<TIntegral, TSize>::debug(const unichar* msg_a) const {

  // declare local variables
  //
  String output;
  String value;
  
  // dump the data
  //
  value.assign((TIntegral)value_d);
  output.debugStr(name(), msg_a, L"value_d", value);
  Console::put(output);

  // exit gracefully
  //
  return true;
}

//-----------------------------------------------------------------------------
//
// uniform random number generation
//      
//-----------------------------------------------------------------------------

// method: rand
//
// arguments:
//  Random& generator: (input) random number generator
//
// return: a random number
//
// this is the default method that should never be called.
//
template<class TIntegral, class TSize>
TIntegral MScalar<TIntegral, TSize>::rand(Random& generator_a) {
  Error::handle(name(), L"rand", Error::TEMPLATE_TYPE, __FILE__, __LINE__);
  return 0;
}

// ifdef so that the specializations will only be compiled
// for the given type.
//
#ifdef ISIP_TEMPLATE_byte_byte8

// method: rand
//
// arguments:
//  Random& generator: (input) random number generator
//
// return: a random number represented as a byte
//
template<>
byte MScalar<byte, byte8>::rand(Random& generator_a) {
  return (value_d =
	  (byte)(generator_a.get() * RAND_BYTE_MAX));
}

#elif defined ISIP_TEMPLATE_ushort_uint16

// method: rand
//
// arguments:
//  Random& generator: (input) random number generator
//
// return: a random number represented as a ushort
//
template<>
ushort MScalar<ushort, uint16>::rand(Random& generator_a) {
  return (value_d =
	  (ushort)Integral::round((generator_a.get() * RAND_USHORT_MAX)));
}

#elif defined ISIP_TEMPLATE_ulong_uint32

// method: rand
//
// arguments:
//  Random& generator: (input) random number generator
//
// return: a random number represented as a ulong
//
template<>
ulong MScalar<ulong, uint32>::rand(Random& generator_a) {
  return (value_d =
	  (ulong)Integral::round((generator_a.get() * RAND_ULONG_MAX)));
}

#elif defined ISIP_TEMPLATE_ullong_uint64

// method: rand
//
// arguments:
//  Random& generator: (input) random number generator
//
// return: a random number represented as a ullong
//
template<>
ullong MScalar<ullong, uint64>::rand(Random& generator_a) {
  return (value_d =
	  (ullong)Integral::round((generator_a.get() * RAND_ULLONG_MAX)));
}

#elif defined ISIP_TEMPLATE_short_int16

// method: rand
//
// arguments:
//  Random& generator: (input) random number generator
//
// return: a random number represented as a short
//
template<>
short MScalar<short, int16>::rand(Random& generator_a) {
  return (value_d =
	  (short)Integral::round(((generator_a.get() - 0.5) *
				  2.0 * RAND_SHORT_MAX)));
}

#elif defined ISIP_TEMPLATE_long_int32

// method: rand
//
// arguments:
//  Random& generator: (input) random number generator
//
// return: a random number represented as a long
//
template<>
long MScalar<long, int32>::rand(Random& generator_a) {
  return (value_d =
	  (long)Integral::round(((generator_a.get() - 0.5) *
				2.0 * RAND_LONG_MAX)));
}

#elif defined ISIP_TEMPLATE_llong_int64

// method: rand
//
// arguments:
//  Random& generator: (input) random number generator
//
// return: a random number represented as a llong
//
template<>
llong MScalar<llong, int64>::rand(Random& generator_a) {
  return (value_d =
	  (llong)Integral::round(((generator_a.get() - 0.5) *
				  2.0 * RAND_LLONG_MAX)));
}

#elif defined ISIP_TEMPLATE_float_float32

// method: rand
//
// arguments:
//  Random& generator: (input) random number generator
//
// return: a random number represented as a float
//
template<>
float MScalar<float, float32>::rand(Random& generator_a) {
  return (value_d = (float)(generator_a.get()));
}

#elif defined ISIP_TEMPLATE_double_float64

// method: rand
//
// arguments:
//  Random& generator: (input) random number generator
//
// return: a random number represented as a double
//
template<>
double MScalar<double, float64>::rand(Random& generator_a) {
  return (value_d = generator_a.get());
}

#endif

// method: rand
//
// arguments:
//  TIntegral min: (input) lower bound
//  TIntegral max: (input) upper bound
//  Random& generator: (input) random number generator
//
// return: a random number
//
// this method finds a random number within the range (min, max)
//
template<class TIntegral, class TSize>
TIntegral MScalar<TIntegral, TSize>::rand(TIntegral min_a, TIntegral max_a,
					  Random& generator_a) {

  // bounds checking
  //
  if (min_a > max_a) {
    return Error::handle(name(), L"rand", Error::ARG, __FILE__, __LINE__);
  }

  // scale by a double
  //
  return (value_d = (TIntegral)(generator_a.get() 
				* (double)(max_a - min_a)) + min_a);
}

//-----------------------------------------------------------------------------
//
// gaussian random number generation
//      
//-----------------------------------------------------------------------------

// method: grand
//
// arguments:
//  TIntegral mean: (input) mean of the distribution
//  TIntegral stddev: (input) standard deviation
//  Random& generator: (input) random number generator
//
// return: a random number
//
// this is the default method.
//
template<class TIntegral, class TSize>
TIntegral MScalar<TIntegral, TSize>::grand(TIntegral mean_a,
					   TIntegral stddev_a,
					   Random& generator_a) {

  // return a random number
  //
  return (value_d = (TIntegral)(generator_a.get() * (double)stddev_a +
				(double)mean_a));
}

// ifdef so that the specializations will only be compiled
// for the given type.
//
#if defined ISIP_TEMPLATE_byte_byte8

// method: grand
//
// arguments:
//  byte mean: (input) mean of the distribution
//  byte stddev: (input) standard deviation
//  Random& generator: (input) random number generator
//
// return: a random number represented as a byte
//
template<>
byte MScalar<byte, byte8>::grand(byte mean_a, byte stddev_a,
				 Random& generator_a) {
  // declare local variables
  //
  double value;

  // loop until we find a satisfactory random number
  //
  do {
    value = generator_a.get() * (double)stddev_a + (double)mean_a;
  } while ((value < 0) || (value > Integral::TWO_EXP8));

  // exit gracefully
  //
  return (value_d = (byte)value);
}

#elif defined ISIP_TEMPLATE_ushort_uint16

// method: grand
//
// arguments:
//  ushort mean: (input) mean of the distribution
//  ushort stddev: (input) standard deviation
//  Random& generator: (input) random number generator
//
// return: a random number represented as a ushort
//
template<>
ushort MScalar<ushort, uint16>::grand(ushort mean_a, ushort stddev_a,
				      Random& generator_a) {

  // declare local variables
  //
  double value;

  // loop until we find a satisfactory random number
  //
  do {
    value = generator_a.get() * (double)stddev_a + (double)mean_a;
  } while ((value < 0) || (value > Integral::TWO_EXP16));

  // exit gracefully
  //
  return (value_d = (ushort)value);
}

#elif defined ISIP_TEMPLATE_ulong_uint32

// method: grand
//
// arguments:
//  ulong mean: (input) mean of the distribution
//  ulong stddev: (input) standard deviation
//  Random& generator: (input) random number generator
//
// return: a random number represented as a ulong
//
template<>
ulong MScalar<ulong, uint32>::grand(ulong mean_a, ulong stddev_a,
				    Random& generator_a) {

  // declare local variables
  //
  double value;

  // loop until we find a satisfactory random number
  //
  do {
    value = generator_a.get() * (double)stddev_a + (double)mean_a;
  } while ((value < 0) || (value > Integral::TWO_EXP8));

  // exit gracefully
  //
  return value_d = ((ulong)value);
}

#elif defined ISIP_TEMPLATE_ullong_uint64

// method: grand
//
// arguments:
//  ullong mean: (input) mean of the distribution
//  ullong stddev: (input) standard deviation
//  Random& generator: (input) random number generator
//
// return: a random number represented as a ullong
//
template<>
ullong MScalar<ullong, uint64>::grand(ullong mean_a, ullong stddev_a,
				      Random& generator_a) {

  // declare local variables
  //
  double value;

  // loop until we find a satisfactory random number
  //
  do {
    value = generator_a.get() * (double)stddev_a + (double)mean_a;
  } while ((value < 0) || (value > Integral::TWO_EXP32));

  // exit gracefully
  //
  return value_d = ((ullong)value);
}

#endif

//-----------------------------------------------------------------------------
//
// we define non-integral constants in the default constructor
//      
//-----------------------------------------------------------------------------

// constants: class name
//
template<class TIntegral, class TSize>
const String MScalar<TIntegral, TSize>::CLASS_NAME(L"MScalar");


// constants: default value
//
template<class TIntegral, class TSize>
const TIntegral MScalar<TIntegral, TSize>::DEF_VALUE(0);

// constants: default parameters
//
template<class TIntegral, class TSize>
const String MScalar<TIntegral, TSize>::DEF_PARAM(L"value");

// static instantiations: debug level
//
template<class TIntegral, class TSize>
Integral::DEBUG MScalar<TIntegral, TSize>::debug_level_d = Integral::NONE;

//-----------------------------------------------------------------------------
//
// explicit class template instantiations - must come at the end
//      
//-----------------------------------------------------------------------------

// define all pre-provided template instances
//
template class MScalar<ISIP_TEMPLATE_TARGET>;

//
// end of file

