Max value of an integer type?

  • Thread starter Frederick Gotham
  • Start date
F

Frederick Gotham

I'm writing a template, and I need to know the maximum value of a given
integer type at compile time. something like:

template<class NumType>
class Arb {
public:

static NumType const max = /* maximum value */;

};


If the template were only to be used with unsigned integer types, then
I'd do the following:

template<class NumType>
class Arb {
public:

static NumType const max = -1;

};


I need a compile-time constant which evaluates to the maximum value of an
integer type.

Any ideas?

If it weren't undefined behaviour to overflow a signed integer, I could
use a metaprogramming technique such as the following:

template<class T, bool overflow = false>
struct MaxIntVal {
private:

static T const internal = 1 + MaxIntVal<T,...

public:

static T const val = SCHAR_MAX + internal;
};
 
A

Alf P. Steinbach

* Frederick Gotham:
I'm writing a template, and I need to know the maximum value of a given
integer type at compile time.

template< typename T > struct Max;
template<> struct Max<int>{ static int const value = INT_MAX; };
and so on
 
I

Ian Collins

Frederick said:
I need a compile-time constant which evaluates to the maximum value of an
integer type.
Are you sure it has to be compile time? If not just use
std::numeric_limits<T>::max()
 
F

Frederick Gotham

I have a solution (although I intend on making it more compile-time-
efficient as I can assume that "digits" is at least 7).

#include<limits>

template< class T,
T shift_by = 0,
bool no_more_digits = shift_by == std::numeric_limits
struct IntMax {
private:

static T const one = 1;

public:

static T const val = (one << shift_by) | IntMax<T,shift_by +
one>::val;

};

template<class T, T shift_by>
struct IntMax<T,shift_by,true> {

static T const val = 0;
};


#include <iostream>


int main()
{
std::cout <<

"Max values\n"
"============\n\n"

" Signed char: " << (int)IntMax<signed char>::val <<

"\nSigned short: " << IntMax<short>::val <<

"\n Signed int: " << IntMax<int>::val <<

"\n Signed long: " << IntMax<long>::val;

}
 
F

Frederick Gotham

Frederick Gotham posted:
I have a solution (although I intend on making it more compile-time-
efficient as I can assume that "digits" is at least 7).


Here's the more efficient version:


#include<limits>


template< class T,
T shift_by,
bool no_more_digits = shift_by == std::numeric_limits
struct IntMax_Internal {
private:

static T const one = 1;

public:

static T const val = (one << shift_by) | IntMax_Internal<T,shift_by +
one>::val;

};

template<class T, T shift_by>
struct IntMax_Internal<T,shift_by,true> {

static T const val = 0;
};

template< class T >
struct IntMax {
private:

static T const one_two_seven = 127;

public:

static T const val = one_two_seven | IntMax_Internal<T,7>::val;
};


#include <iostream>


int main()
{
std::cout <<

"Max values\n"
"==========\n\n"

" Unsigned char: " << (int)IntMax<unsigned char>::val <<

"\nUnsigned short: " << IntMax<unsigned short>::val <<

"\n Unsigned int: " << IntMax<unsigned>::val <<

"\n Unsigned long: " << IntMax<unsigned long>::val <<

"\n\n Signed char: " << (int)IntMax<signed char>::val <<

"\n Signed short: " << IntMax<short>::val <<

"\n Signed int: " << IntMax<int>::val <<

"\n Signed long: " << IntMax<long>::val;

}
 
G

gottlobfrege

Frederick said:
template< class T,
T shift_by,
bool no_more_digits = shift_by == std::numeric_limits
....

Although this would probably work 99% of the time, I think technically
that the standard does not require 2s compliment arithmetic (or
whatever it is called) - ie you can't assume setting all bits to 1
gives you the largest value.


As mentioned earlier, I think you would be better using INT_MAX, etc in
a bunch of specializations.


If you wanted to get really perverse, you might be able to do something
somehow similar to using bits - recursively double the value until it
doesn't get bigger, then (restore last largest value and) start adding
half as much, then 1/4, etc until you are not adding anything.

eg if max is 20 (strange max!)

search = 1;
try adding 2? => search = 3;
+ 4 ? => search = 7;
+ 8 ? => search = 15;
+ 16 ? => overflow!! - back off!
+ 8 ? => overflow!!
+ 4 ? => search = 19
+ 2 ? => overflow!
+ 1 ? => search = 20.
stop because you are at 1. If there was 'room' to add another 1, then
+ 2 would have worked.

Anyhow, perserve, and not really understandable by the next coder who
looks at it - even if that is you 2 years from now. But I suspect it
could be coded with templates.

Of course, I don't know what the standard says will happen when compile
time constants 'overflow'....

- Tony
 
G

Guest

Frederick said:
I have a solution (although I intend on making it more compile-time-
efficient as I can assume that "digits" is at least 7).

#include<limits>

template< class T,
T shift_by = 0,
bool no_more_digits = shift_by == std::numeric_limits

struct IntMax {
private:

static T const one = 1;

public:

static T const val = (one << shift_by) | IntMax<T,shift_by +
one>::val;

};

template<class T, T shift_by>
struct IntMax<T,shift_by,true> {

static T const val = 0;
};

If you can use numeric_limits::digits, wouldn't this be simpler?

template <typename T>
struct intinfo {
static const T max = (static_cast<T>(1) <<
std::numeric_limits<T>::digits - 1) - 1 << 1 | 1;
};

Or are there some special cases this doesn't handle correctly?
 
R

Rolf Magnus

Ian said:
Are you sure it has to be compile time? If not just use
std::numeric_limits<T>::max()

I guess there must be a good reason why this is not a compile-time constant,
but a function. I don't think that there could be an implementation where
those values change during runtime, so what is the reason to make it a
function?
 
F

Frederick Gotham

posted:
...

Although this would probably work 99% of the time, I think technically
that the standard does not require 2s compliment arithmetic (or
whatever it is called) - ie you can't assume setting all bits to 1
gives you the largest value.


"digits" gives you the amount of value bits, excluding the sign bit.

If the sign bit (if any) is zero, and if all the rest of the bits are 1,
then you have the max value.
 
F

Frederick Gotham

=?utf-8?B?SGFyYWxkIHZhbiBExLNr?= posted:

If you can use numeric_limits::digits, wouldn't this be simpler?

template <typename T>
struct intinfo {
static const T max = (static_cast<T>(1) <<
std::numeric_limits<T>::digits - 1) - 1 << 1 | 1;
};

Or are there some special cases this doesn't handle correctly?


That's brilliant. Here's the updated code:

#include<limits>

template<class T>
struct IntMax {
private:

static T const MSBOnly = static_cast<T>(1) << std::numeric_limits
<T>::digits - 1;

public:

static T const val = MSBOnly | MSBOnly - 1;

};


#include <iostream>


int main()
{
std::cout <<

"Max values\n"
"==========\n\n"

" Unsigned char: " << (int)IntMax<unsigned char>::val <<

"\nUnsigned short: " << IntMax<unsigned short>::val <<

"\n Unsigned int: " << IntMax<unsigned>::val <<

"\n Unsigned long: " << IntMax<unsigned long>::val <<

"\n\n Signed char: " << (int)IntMax<signed char>::val <<

"\n Signed short: " << IntMax<short>::val <<

"\n Signed int: " << IntMax<int>::val <<

"\n Signed long: " << IntMax<long>::val;

}
 
B

Bo Persson

Frederick Gotham said:
posted:



"digits" gives you the amount of value bits, excluding the sign bit.

If the sign bit (if any) is zero, and if all the rest of the bits
are 1,
then you have the max value.

This of course assumes that all the bits take part in the value
representation. Not a requirement.

You are now at 99.5% mark, I guess. :)


There is a reason for the seemingly redundant values in
numeric_limits - implementations are allowed to have unusual values
for some of them.


Bo Persson
 
R

Rolf Magnus

Bo said:
This of course assumes that all the bits take part in the value
representation.

AFAICS, it doesn't. As Frederick wrote, "digits" gives you the amount of
_value bits_, not the total amount of bits.
 
F

Frederick Gotham

Bo Persson posted:
This of course assumes that all the bits take part in the value
representation. Not a requirement.


18.2.1.2 numeric_limits members

static const int digits;

6 Number of radix digits that can be represented without change.
7 For built-in integer types, the number of non-sign bits in the
representation.
 
A

Alf P. Steinbach

* Frederick Gotham:
=?utf-8?B?SGFyYWxkIHZhbiBExLNr?= posted:




That's brilliant. Here's the updated code:

#include<limits>

template<class T>
struct IntMax {
private:

static T const MSBOnly = static_cast<T>(1) << std::numeric_limits
<T>::digits - 1;

public:

static T const val = MSBOnly | MSBOnly - 1;

};

It's good fun to throw academic spanners into practical wheels, so,
where does the standard exclude a grey-code representation? ;-)
 
F

Frederick Gotham

Alf P. Steinbach posted:

It's good fun to throw academic spanners into practical wheels, so,
where does the standard exclude a grey-code representation? ;-)


Only caveat that comes to mind is negative zero... but that shouldn't be an
issue here.

Unless you're talking about left-shifting a signed integer type... ?


(Not quite sure what you mean by "exclude a grey-code representation")
 
A

Alf P. Steinbach

* Frederick Gotham:
Alf P. Steinbach posted:




Only caveat that comes to mind is negative zero... but that shouldn't be an
issue here.

Unless you're talking about left-shifting a signed integer type... ?


(Not quite sure what you mean by "exclude a grey-code representation")

Frederick, I give you also (as I gave Protoman)... WIKIPEDIA!

<url: http://en.wikipedia.org/wiki/Grey_code>

Note the bit pattern for the highest value when using a given number of
bits.

Sorry for the typo.

Coming from a whaling country, I naturally prefer Earl Grey tea...
 
F

Frederick Gotham

Alf P. Steinbach posted:
Note the bit pattern for the highest value when using a given number of
bits.


I was under the assumption that C++ had to store positive values as
follows:

0: 0000
1: 0001
2: 0010
3: 0011
4: 0100
5: 0101
6: 0110
7: 0111
8: 1000
9: 1001
10: 1010
11: 1011
12: 1100
13: 1101
14: 1110
15: 1111

Are you saying that:

(A) The machine could use another method such as "Gray code".
and
(B) My code could break on other systems, and thus isn't trully
portable?
 
R

Rolf Magnus

Alf said:
It's good fun to throw academic spanners into practical wheels, so,
where does the standard exclude a grey-code representation? ;-)

Hmm, I would have said 3.9.1/7, but after reading it again, it seems that
this actually doesn't prohibit a grey-code representation.
 
R

Rolf Magnus

Rolf said:
Hmm, I would have said 3.9.1/7, but after reading it again, it seems that
this actually doesn't prohibit a grey-code representation.

Ok, now I have one: 5.8/2.
 
F

Frederick Gotham

Rolf Magnus posted:

Ok, now I have one: 5.8/2.

The value of E1 << E2 is E1 (interpreted as a bit pattern) left-shifted E2
bit positions; vacated bits are zero-filled. If E1 has an unsigned type,
the value of the result is E1 multiplied by the quantity 2 raised to the
power E2, reduced modulo ULONG_MAX+1 if E1 has type unsigned long,
UINT_MAX+1 otherwise.


Is it the "vacated bits are zero-filled" part that you're talking about?
 

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

No members online now.

Forum statistics

Threads
473,776
Messages
2,569,603
Members
45,186
Latest member
vinaykumar_nevatia

Latest Threads

Top