template computed alternative to numeric_limits<T>

G

Gianni Mariani

The spirit of this arguably pointless exercise, is that the
numeric_limits<T> class could be replaced with a totally generic
template of compile-time, template computed constants.

The problem is that it takes a *long* time to compile and the "long
double" version instantiates so many classes that gcc runs out of memory
on my 1 gig machine !

So the question is - is there a simple way to reduce the number of
template instantiations from O(N) to O(logN) ?



#include <iostream>
#include <limits>


template <typename T, int N>
struct pow_m
{
static const T value =
( ( pow_m<T, N-1>::value * 2 ) + static_cast<T>( 1 ) ) -
static_cast<T>( 1 )
== ( pow_m<T, N-1>::value * 2 )
? ( pow_m<T, N-1>::value * 2 ) + static_cast<T>( 1 )
: ( pow_m<T, N-1>::value * 2 );

static const T valuep1 = ( value * 2 );
};

template <typename T>
struct pow_m<T, 0>
{
static const T value = static_cast<T>( 1 );
static const T valuep1 = ( value * 2 ) + static_cast<T>( 1 );
};

template <typename T, int N, bool v> struct max_f;

template <typename T, int N>
struct max_f<T,N,true>
{
static const T max_value = pow_m<T,N-1>::value;

static const int max_exponent = N-1;
};

template <typename T, int N, bool v>
struct max_f : max_f<T, N+1, pow_m<T, N+1>::value == pow_m<T,
N+1>::valuep1 >
{
};

template <typename T, int N>
struct pow_nm
{
static const T value =
( ( pow_nm<T, N-1>::value * 2 ) + static_cast<T>( -1 ) ) -
static_cast<T>( -1 )
== ( pow_nm<T, N-1>::value * 2 )
? ( pow_nm<T, N-1>::value * 2 ) + static_cast<T>( -1 )
: ( pow_nm<T, N-1>::value * 2 );

static const T valuep1 = ( value * 2 );
};

template <typename T>
struct pow_nm<T, 0>
{
static const T value = static_cast<T>( -1 );
static const T valuep1 = ( value * 2 ) + static_cast<T>( -1 );
};

template <typename T, int N, bool v> struct max_nm;

template <typename T, int N>
struct max_nm<T,N,true>
{
static const T max_value = pow_nm<T,N-1>::value;

static const int max_exponent = N-1;
};

template <typename T, int N, bool v>
struct max_nm : max_nm<T, N+1, pow_nm<T, N+1>::value == pow_nm<T,
N+1>::valuep1 >
{
};

template<typename T>
struct max_limit
{
static const int max_exponent = max_f<T,0,false>::max_exponent;
static const T max_value = max_f<T,0,false>::max_value;

static const int neg_max_exponent = max_nm<T,0,false>::max_exponent;
static const T neg_max_value = max_nm<T,0,false>::max_value;

};

int main()
{
std::cout << "Positive maximum\n";
std::cout << "Float\n";
std::cout << max_limit< float >::max_exponent << "\n";
std::cout << max_limit< float >::max_value << "\n";

std::cout << "Double\n";
std::cout << max_limit< double >::max_exponent << "\n";
std::cout << max_limit< double >::max_value << "\n";

std::cout << "limits max says " <<
std::numeric_limits<double>::max() << "\n";
std::cout << "limits/template diff " << (
std::numeric_limits<double>::max() - max_limit< double >::max_value ) <<
"\n";

std::cout << "Negative maximum\n";


std::cout << "Float\n";
std::cout << max_limit< float >::neg_max_exponent << "\n";
std::cout << max_limit< float >::neg_max_value << "\n";

std::cout << "Double\n";
std::cout << max_limit< double >::neg_max_exponent << "\n";
std::cout << max_limit< double >::neg_max_value << "\n";
/*
std::cout << "Long Double\n";
std::cout << max_limit< long double >::max_exponent << "\n";
std::cout << max_limit< long double >::max_value << "\n";
*/
}
 
A

Alan

Gianni Mariani said:
The spirit of this arguably pointless exercise, is that the
numeric_limits<T> class could be replaced with a totally generic
template of compile-time, template computed constants.

The problem is that it takes a *long* time to compile and the "long
[snip]

I don't know anything about templates (yet) but this DMC
(Digital Mars) compiler complains that static members should
initialised outside of the structures. I may not be the smartest
of C++ programers but I seem to remember that this is also
the way with 'ordinary' classes ;-)

Alan
 
G

Gianni Mariani

Alan said:
Gianni Mariani said:
The spirit of this arguably pointless exercise, is that the
numeric_limits<T> class could be replaced with a totally generic
template of compile-time, template computed constants.

The problem is that it takes a *long* time to compile and the "long

[snip]

I don't know anything about templates (yet) but this DMC
(Digital Mars) compiler complains that static members should
initialised outside of the structures. I may not be the smartest
of C++ programers but I seem to remember that this is also
the way with 'ordinary' classes ;-)

OK - here is a version that might work for you:


#include <iostream>
#include <limits>


template <typename T, int N>
struct pow_m
{
static const T value;

static const T valuep1;
};

template <typename T, int N>
const T pow_m<T,N>::value =
( ( pow_m<T, N-1>::value * 2 ) + static_cast<T>( 1 ) ) -
static_cast<T>( 1 )
== ( pow_m<T, N-1>::value * 2 )
? ( pow_m<T, N-1>::value * 2 ) + static_cast<T>( 1 )
: ( pow_m<T, N-1>::value * 2 );

template <typename T, int N>
const T pow_m<T,N>::valuep1 = ( value * 2 );

template <typename T>
struct pow_m<T, 0>
{
static const T value;
static const T valuep1;
};

template <typename T>
const T pow_m<T, 0>::value = static_cast<T>( 1 );
template <typename T>
const T pow_m<T, 0>::valuep1 = ( value * 2 ) + static_cast<T>( 1 );

template <typename T, int N, bool v> struct max_f;

template <typename T, int N>
struct max_f<T,N,true>
{
static const T max_value;

static const int max_exponent;
};
template <typename T, int N>
const T max_f<T,N,true>::max_value = pow_m<T,N-1>::value;

template <typename T, int N>
const int max_f<T,N,true>::max_exponent = N-1;

template <typename T, int N>
struct eval_f
{
static const bool at_limit = ( pow_m<T, N+1>::value == pow_m<T,
N+1>::valuep1 );
};

template <typename T, int N, bool v>
struct max_f : max_f<T, N+1, eval_f<T,N>::at_limit >
{
};

template <typename T, int N>
struct pow_nm
{
static const T value;

static const T valuep1;

};

template <typename T, int N>
const T pow_nm<T,N>::value =
( ( pow_nm<T, N-1>::value * 2 ) + static_cast<T>( -1 ) ) -
static_cast<T>( -1 )
== ( pow_nm<T, N-1>::value * 2 )
? ( pow_nm<T, N-1>::value * 2 ) + static_cast<T>( -1 )
: ( pow_nm<T, N-1>::value * 2 );

template <typename T, int N>
const T pow_nm<T,N>::valuep1 = ( value * 2 );

template <typename T>
struct pow_nm<T, 0>
{
static const T value;
static const T valuep1;
};
template <typename T>
const T pow_nm<T, 0>::value = static_cast<T>( -1 );
template <typename T>
const T pow_nm<T, 0>::valuep1 = ( value * 2 ) + static_cast<T>( -1 );

template <typename T, int N, bool v> struct max_nm;

template <typename T, int N>
struct max_nm<T,N,true>
{
static const T max_value;

static const int max_exponent;
};

template <typename T, int N>
const T max_nm<T,N,true>::max_value = pow_nm<T,N-1>::value;

template <typename T, int N>
const int max_nm<T,N,true>::max_exponent = N-1;

template <typename T, int N>
struct eval_nm
{
static const bool at_limit = ( pow_nm<T, N+1>::value == pow_nm<T,
N+1>::valuep1 );
};

template <typename T, int N, bool v>
struct max_nm : max_nm<T, N+1, eval_nm<T,N>::at_limit >
{
};

template<typename T>
struct max_limit
{
static const int max_exponent;
static const T max_value;

static const int neg_max_exponent;
static const T neg_max_value;

};

template<typename T>
const int max_limit<T>::max_exponent = max_f<T,0,false>::max_exponent;
template<typename T>
const T max_limit<T>::max_value = max_f<T,0,false>::max_value;

template<typename T>
const int max_limit<T>::neg_max_exponent =
max_nm<T,0,false>::max_exponent;
template<typename T>
const T max_limit<T>::neg_max_value = max_nm<T,0,false>::max_value;

int main()
{
std::cout << "Positive maximum\n";
std::cout << "Float\n";
std::cout << max_limit< float >::max_exponent << "\n";
std::cout << max_limit< float >::max_value << "\n";

std::cout << "Double\n";
std::cout << max_limit< double >::max_exponent << "\n";
std::cout << max_limit< double >::max_value << "\n";

std::cout << "limits max says " <<
std::numeric_limits<double>::max() << "\n";
std::cout << "limits/template diff " << (
std::numeric_limits<double>::max() - max_limit< double >::max_value ) <<
"\n";

std::cout << "Negative maximum\n";


std::cout << "Float\n";
std::cout << max_limit< float >::neg_max_exponent << "\n";
std::cout << max_limit< float >::neg_max_value << "\n";

std::cout << "Double\n";
std::cout << max_limit< double >::neg_max_exponent << "\n";
std::cout << max_limit< double >::neg_max_value << "\n";
/*
std::cout << "Long Double\n";
std::cout << max_limit< long double >::max_exponent << "\n";
std::cout << max_limit< long double >::max_value << "\n";
*/
}
 
A

Alan

Gianni Mariani said:
Alan said:
Gianni Mariani said:
The spirit of this arguably pointless exercise, is that the
numeric_limits<T> class could be replaced with a totally generic
template of compile-time, template computed constants.

The problem is that it takes a *long* time to compile and the "long

[snip]

I don't know anything about templates (yet) but this DMC
(Digital Mars) compiler complains that static members should
initialised outside of the structures. I may not be the smartest
of C++ programers but I seem to remember that this is also
the way with 'ordinary' classes ;-)

OK - here is a version that might work for you:


#include <iostream>
#include <limits>


template <typename T, int N>
struct pow_m
{
static const T value;

static const T valuep1;
};

template <typename T, int N>
const T pow_m<T,N>::value =
( ( pow_m<T, N-1>::value * 2 ) + static_cast<T>( 1 ) ) -
static_cast<T>( 1 )
== ( pow_m<T, N-1>::value * 2 )
? ( pow_m<T, N-1>::value * 2 ) + static_cast<T>( 1 )
: ( pow_m<T, N-1>::value * 2 );

template <typename T, int N>
const T pow_m<T,N>::valuep1 = ( value * 2 );

template <typename T>
struct pow_m<T, 0>
{
static const T value;
static const T valuep1;
};

template <typename T>
const T pow_m<T, 0>::value = static_cast<T>( 1 );
template <typename T>
const T pow_m<T, 0>::valuep1 = ( value * 2 ) + static_cast<T>( 1 );

template <typename T, int N, bool v> struct max_f;

template <typename T, int N>
struct max_f<T,N,true>
{
static const T max_value;

static const int max_exponent;
};
template <typename T, int N>
const T max_f<T,N,true>::max_value = pow_m<T,N-1>::value;

template <typename T, int N>
const int max_f<T,N,true>::max_exponent = N-1;

template <typename T, int N>
struct eval_f
{
static const bool at_limit = ( pow_m<T, N+1>::value == pow_m<T,
N+1>::valuep1 );
};

template <typename T, int N, bool v>
struct max_f : max_f<T, N+1, eval_f<T,N>::at_limit >
{
};

template <typename T, int N>
struct pow_nm
{
static const T value;

static const T valuep1;

};

template <typename T, int N>
const T pow_nm<T,N>::value =
( ( pow_nm<T, N-1>::value * 2 ) + static_cast<T>( -1 ) ) -
static_cast<T>( -1 )
== ( pow_nm<T, N-1>::value * 2 )
? ( pow_nm<T, N-1>::value * 2 ) + static_cast<T>( -1 )
: ( pow_nm<T, N-1>::value * 2 );

template <typename T, int N>
const T pow_nm<T,N>::valuep1 = ( value * 2 );

template <typename T>
struct pow_nm<T, 0>
{
static const T value;
static const T valuep1;
};
template <typename T>
const T pow_nm<T, 0>::value = static_cast<T>( -1 );
template <typename T>
const T pow_nm<T, 0>::valuep1 = ( value * 2 ) + static_cast<T>( -1 );

template <typename T, int N, bool v> struct max_nm;

template <typename T, int N>
struct max_nm<T,N,true>
{
static const T max_value;

static const int max_exponent;
};

template <typename T, int N>
const T max_nm<T,N,true>::max_value = pow_nm<T,N-1>::value;

template <typename T, int N>
const int max_nm<T,N,true>::max_exponent = N-1;

template <typename T, int N>
struct eval_nm
{
static const bool at_limit = ( pow_nm<T, N+1>::value == pow_nm<T,
N+1>::valuep1 );
};

template <typename T, int N, bool v>
struct max_nm : max_nm<T, N+1, eval_nm<T,N>::at_limit >
{
};

template<typename T>
struct max_limit
{
static const int max_exponent;
static const T max_value;

static const int neg_max_exponent;
static const T neg_max_value;

};

template<typename T>
const int max_limit<T>::max_exponent = max_f<T,0,false>::max_exponent;
template<typename T>
const T max_limit<T>::max_value = max_f<T,0,false>::max_value;

template<typename T>
const int max_limit<T>::neg_max_exponent =
max_nm<T,0,false>::max_exponent;
template<typename T>
const T max_limit<T>::neg_max_value = max_nm<T,0,false>::max_value;

int main()
{
std::cout << "Positive maximum\n";
std::cout << "Float\n";
std::cout << max_limit< float >::max_exponent << "\n";
std::cout << max_limit< float >::max_value << "\n";

std::cout << "Double\n";
std::cout << max_limit< double >::max_exponent << "\n";
std::cout << max_limit< double >::max_value << "\n";

std::cout << "limits max says " <<
std::numeric_limits<double>::max() << "\n";
std::cout << "limits/template diff " <<
std::numeric_limits<double>::max() - max_limit< double >::max_value ) <<
"\n";

std::cout << "Negative maximum\n";


std::cout << "Float\n";
std::cout << max_limit< float >::neg_max_exponent << "\n";
std::cout << max_limit< float >::neg_max_value << "\n";

std::cout << "Double\n";
std::cout << max_limit< double >::neg_max_exponent << "\n";
std::cout << max_limit< double >::neg_max_value << "\n";

std::cout << "Long Double\n";
std::cout << max_limit< long double >::max_exponent << "\n";
std::cout << max_limit< long double >::max_value << "\n";

}

Complains:
Line 55: in-class initializer for const at_limit not constant
Line 59: constant initializer expected

Alan
 
G

Gianni Mariani

Alan said:
Complains:
Line 55: in-class initializer for const at_limit not constant
Line 59: constant initializer expected

Now the question is, it that legal ?

GCC compiles it just fine.
 
A

Alan

Gianni Mariani said:
Now the question is, it that legal ?

GCC compiles it just fine.

I'm not the person to answer your question.

But does it still "takes a *long* time to compile and the "long double"
version instantiates so many classes that gcc runs out of memory
on my 1 gig machine !" ?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,011
Latest member
AjaUqq1950

Latest Threads

Top