//------------------------------------------------------------------------------
// module util.cpp version 2.0b //
// //
// general utilities //
// //
// copyright (c) 1998-2003 by Lars Haendel //
// home: www.newty.de //
// //
// This program is free software and can be used under the terms of the //
// GNU licence. See header-file for further information and disclaimer. //
// //
//------------------------------------------------------------------------------
#include <limits> // due to INT_MAX
#include <math> // sqrt()
#include <stdio> // sprintf()
#include <values> // MAXFLOAT
#include "util.h"
#include "defines.h"
//----------------------------------------------------------------------------------------------------------------------
// write time stamp to static variable
const char* TimeStamp()
{
static char szText[256];
time_t _tstamp = time(NULL);
tm* tstamp = localtime(&_tstamp);
sprintf(szText, "%.2d.%.2d.%d %.2d:%.2d", tstamp->tm_mday, tstamp->tm_mon+1, tstamp->tm_year+1900
, tstamp->tm_hour, tstamp->tm_min);
return szText;
}
//----------------------------------------------------------------------------------------------------------------------
// write given value to 'text' using the specified precision counted from the most signifcant digit. Reduce precision
// if diplayed digits at the end would be "0". Example with _prec=1: 0.002545 -> "0.0025", 0.00203 -> "0.002"
void ValueToText(const float value, char* text, const int width /*=0*/, const int _prec /*=0*/)
{
int prec=_prec; // ini
if(value == MAXFLOAT)
sprintf(text, "%*s", width, "oo"); // 1. 'oo' for infinity
else
{
if(value==0) // 2. set precision to 0 for zero
prec=0;
// 3. all other cases ...
else
{
// a) add precision depending on most significant digit
if(value < (float) 0.01)
prec+=3;
else
if(value < (float) 0.1)
prec+=2;
else
if(value < (float) 1.0)
prec+=1;
// b) reduce precision if displayed values would be "0"
for(int i=0;i<_prec;i++)
{
int fac1 = pow(10, prec-1); // pre-calculate to save some time
int fac2 = fac1*10;
float r2 = floor(0.5+value*fac2)/fac2; // round to actual precision and ...
float r1 = floor(0.5+value*fac1)/fac1; // ... to actual precision minus one
if(r1==r2) // if next // reduce precision by one if rounded values are equal
prec--;
else
break;
}
}
// c) write text using sprintf()
sprintf(text, "%*.*f", width, prec, value);
}
}
//----------------------------------------------------------------------------------------------------------------------
// write given value static variable 1 and return pointer to it
const char* ValueToText1(const float value, const int width /*=0*/, const int prec /*=0*/
, const bool& f_SpecialMinusOne/*=false*/)
{
static char szText[STS];
if(f_SpecialMinusOne && value==-1) // if enabled: treat value of '-1' as unknown
strcpy(szText, "NA");
else
ValueToText(value, szText, width, prec);
return szText;
}
//----------------------------------------------------------------------------------------------------------------------
// write given value to static variable 2 and return pointer to it
const char* ValueToText2(const float value, const int width /*=0*/, const int prec /*=0*/
, const bool& f_SpecialMinusOne)
{
static char szText[STS];
if(f_SpecialMinusOne && value==-1) // if enabled: treat value of '-1' as unknown
strcpy(szText, "NA");
else
ValueToText(value, szText, width, prec);
return szText;
}
//----------------------------------------------------------------------------------------------------------------------
// write given value (using a fixed floating point precision) to static variable and return pointer to it
const char* ValueToTextFP(const float value, const int width /*=0*/, const int prec /*=0*/)
{
static char szText[STS];
sprintf(szText, "%*.*f", width, prec, value);
return szText;
}
//----------------------------------------------------------------------------------------------------------------------
// write value between 0 and 1 like 0.57 as string '57.1%'
const char* WritePercentage(const float& value, const int& width/*=0*/, const int& prec/*=1*/
, const bool& f_PercentChar/*=false*/)
{
static char szText[STS];
if(value<0 || value>1)
strcpy(szText, "NA");
else
if(f_PercentChar)
sprintf(szText, "%*.*f %%", width, prec, 100*value);
else
sprintf(szText, "%*.*f", width, prec, 100*value);
return szText;
}
//----------------------------------------------------------------------------------------------------------------------
// write time formatted to static variable and return pointer to it
const char* WriteTime(const clock_t& time, const bool& f_Justified)
{
static char szText[STS];
float t=time/((float) CLK_TCK); // time in seconds
if(t<0.001) sprintf(szText, "%*s" , 8*f_Justified, "--"); // less than a milli second
else if(t<1) sprintf(szText, "%*.0fms" , 6*f_Justified, t*1000.0); // less than a second
else if(t<60) sprintf(szText, "%*.1fs" , 7*f_Justified, t); // less than a minute
else if(t<3600) sprintf(szText, "%*dm%02ds", 4*f_Justified, ((int) t/60), div(t, 60).rem);// less than an hour
else sprintf(szText, "%*dh%02dm", 4*f_Justified, ((int) t/3600), div(t, 3600).rem/60);
return szText;
}
//----------------------------------------------------------------------------------------------------------------------
// write time as hours, minutes and seconds (but no milli seconds) to static text
const char* WriteTime2(const clock_t& time)
{
static char szText[STS];
int t=time/((float) CLK_TCK); // time in seconds
if(t<3600) sprintf(szText, "%dm%02ds", t/60, div(t, 60).rem); // less than an hour
else sprintf(szText, "%dh%02dm%02ds", t/3600, div(t, 3600).rem/60, div(t, 60).rem); // more than an hour
return szText;
}
//-------------------------------------------------------------------------------------------------------------------
// sort/randomization functions
//
//----------------------------------------------------------------------------------------------------------------------
// constructor
TSorter::TSorter(const int& _size)
{
size=_size;
vec=new TIdVec[size];
for(int i=0;i<size;i++)
{
vec[i].id=i;
vec[i].a = vec[i].b = 0; // reset
}
}
//-------------------------------------------------------------------------------------------------------------------
// comparison function - sorts in ascending(!) order
int __cdecl IdVecCmpAsc(const void* _a, const void* _b)
{
// explicitly cast
const TIdVec* c = (const TIdVec*) _a;
const TIdVec* d = (const TIdVec*) _b;
// compare
if(c->a < d->a)
return -1; // c<d regarding criterion a
else
if(c->a == d->a) // c=d _-> decide by criterion b
if(c->b < d->b)
return -1; // c<d regarding criterion b
else
if(c->b == d->b) // equality -> decide by id
if(c->id < d->id)
return 1;
else
return -1;
else
return 1; // c>d regarding criterion b
else
return 1; // c>d regarding criterion a
}
//-------------------------------------------------------------------------------------------------------------------
// comparison function - sorts in descending(!) order
int __cdecl IdVecCmpDes(const void* _a, const void* _b)
{
// explicitly cast
const TIdVec* c = (const TIdVec*) _a;
const TIdVec* d = (const TIdVec*) _b;
// compare
if(c->a < d->a)
return 1; // c<d regarding criterion a
else
if(c->a == d->a) // c=d _-> decide by criterion b
if(c->b < d->b)
return 1; // c<d regarding criterion b
else
if(c->b == d->b) // equality -> decide by id
if(c->id < d->id)
return 1;
else
return -1;
else
return -1; // c>d regarding criterion b
else
return -1; // c>d regarding criterion a
}
//-------------------------------------------------------------------------------------------------------------------
// comparison function
int __cdecl FloatCmpDes(const void* _a, const void* _b)
{
// explicitly cast
const float* a = (const float*) _a;
const float* b = (const float*) _b;
// compare
if(*a<*b)
return 1;
else
return -1;
}
//-------------------------------------------------------------------------------------------------------------------
// comparison function (ascending order)
int __cdecl FloatCmpAsc(const void* _a, const void* _b)
{
// explicitly cast
const float* a = (const float*) _a;
const float* b = (const float*) _b;
// compare
if(*a<*b)
return -1;
else
return 1;
}
//----------------------------------------------------------------------------------------------------------------------
// return integer field with random order of the values 0..N-1
int* /*cr*/ RandomId(const int& N, const unsigned int& seed/*=1*/)
{
// a) initialize random number generator to given seed or to random state
if(seed==1)
::randomize();
else
::srand(seed);
// b) create vector with id and random values
TIdVec* vec = new TIdVec[N];
for(int i=0;i<N;i++)
{
vec[i].id = i;
vec[i].a = vec[i].b = random(INT_MAX);
}
// c) sort this vector regarding the random values
qsort((void*) vec, N, sizeof(vec[0]), IdVecCmpDes);
// d) create and initialize vector with random id's
int* id=new int[N];
for(int i=0;i<N;i++)
id[i]=vec[i].id;
// e) release
delete[] vec;
return id;
}
//----------------------------------------------------------------------------------------------------------------------
// return entries of <_vec> in randomized order in a new vector, delete old one
int* /*cr*/ Randomize(int*& /*ce*/ _vec, const int& nId, const unsigned int& seed/*=1*/)
{
// a) initialize random number generator to given seed or to random state
if(seed==1)
::randomize();
else
::srand(seed);
// b) create vector with id's and random values
TIdVec* vec = new TIdVec[nId];
for(int i=0;i<nId;i++)
{
vec[i].id=_vec[i];
vec[i].a = vec[i].b = random(INT_MAX);
}
delete[] _vec;
// c) sort this vector regarding the random values
qsort((void*) vec, nId, sizeof(vec[0]), IdVecCmpDes);
// d) create and initialize vector with random id's
int* id=new int[nId];
for(int i=0;i<nId;i++)
id[i]=vec[i].id;
// e) release
delete[] vec;
return id;
}
//-------------------------------------------------------------------------------------------------------------------
//
// quantization functions
//
//----------------------------------------------------------------------------------------------------------------------
// calculate interval width
const float CalcIntWidth(const float& max, const float& min, const float& N, const bool& f_Integer/*=false*/)
{
if(f_Integer)
return (max-min)/(N-1);
else
return (max-min)/N;
}
//----------------------------------------------------------------------------------------------------------------------
// quantize given value 'x' into one of N equally spaced intervals
int Quant(const float& x, const float& max, const float& min, const float& N, const bool& f_Integer/*=false*/)
{
int id; // interval id e[0..N-1]
// return 0 if maximum equals minimu
if(max==min)
id = 0;
else
{
const float w = CalcIntWidth(max, min, N, f_Integer); // interval width
if(f_Integer)
id = (int) ( (x-min+w/2) / (max-min+w) * N);
else
{
id = (int) ((x-min)/w); // calculate interval id
if(id>=N) id=N-1; // check
if(id <0) id=0;
}
}
return id;
}
//----------------------------------------------------------------------------------------------------------------------
// dequantize: return median value if interval <id>
const float DeQuant(const int& id, const float& max, const float& min, const float& N, const bool& f_Integer)
{
const float w = CalcIntWidth(max, min, N, f_Integer); // interval width
if(f_Integer)
return min + id*w;
else
return min + w/2 + id*w;
}
//----------------------------------------------------------------------------------------------------------------------
// write bits stored in value to cout
void PrintBits(const int& value)
{
for(int i=0;i<MaxBits;i++)
if(IsBitSet(value, i)) cout << "1";
else cout << "0";
}
//----------------------------------------------------------------------------------------------------------------------
// write bits stored in value to ofstream
void WriteBits(ofstream& file, const int& value, const int nBits/*=MaxBits*/)
{
for(int i=0;i<min(MaxBits, nBits);i++)
if(IsBitSet(value, i)) file << "1";
else file << "0";
}