Max value of a variable

E

Eyegor

Hi all,
I wonder what would be the best way to determine the maximum integer
value a variable can store if I do not know in advance the type of a
variable?

I have the following declarations:

/*Defines*/
#define AEI_unit_max 255//4294967295 /*Largest integer representable
by 32 bit AEI_unit*/

/*Type Definitions*/
typedef unsigned long AEI_unit;

I do not know in advance what the user will choose to use for
AEI_unit. common choices are 8/16/32 bit unsigned integers.
Also I do not know the target compiler, 32-bit or 64-bit compilers. I
know that different compilers treat variable differently, see:
http://en.wikipedia.org/wiki/Limits.h

my question is this:
What is the best way to assign a value to AEI_unit_max based on
AEI_unit type?

I tried to declare AEI_unit_max as a variable rather than a #define
and do the following assignment:
AEI_unit_max=(AEI_unit)(-1);
But this does not seem to work, i get gibberish from calculations
which use AEI_unit_max value.
I also tried AEI_unit_max=~0; but again no luck. Are these two methods
compiler/implementation depended? Is there a more elegant way to do
this?

Is including limits.h and using if->then statements with
sizeof(AEI_unit) be the most sure way?

Thanks
 
K

Keith Thompson

Eyegor said:
I wonder what would be the best way to determine the maximum integer
value a variable can store if I do not know in advance the type of a
variable?

I have the following declarations:

/*Defines*/
#define AEI_unit_max 255//4294967295 /*Largest integer representable
by 32 bit AEI_unit*/

/*Type Definitions*/
typedef unsigned long AEI_unit;

I do not know in advance what the user will choose to use for
AEI_unit. common choices are 8/16/32 bit unsigned integers.
Also I do not know the target compiler, 32-bit or 64-bit compilers. I
know that different compilers treat variable differently, see:
http://en.wikipedia.org/wiki/Limits.h

What exactly *do* you know? Do you know that AEI_unit is a typedef for
some unsigned integer type?
my question is this:
What is the best way to assign a value to AEI_unit_max based on
AEI_unit type?

I tried to declare AEI_unit_max as a variable rather than a #define
and do the following assignment:
AEI_unit_max=(AEI_unit)(-1);
But this does not seem to work, i get gibberish from calculations
which use AEI_unit_max value.

That should work. Note that the cast is unnecessary; the value -1 will
be implicitly covnerted to the type of the LHS.
I also tried AEI_unit_max=~0; but again no luck. Are these two methods
compiler/implementation depended? Is there a more elegant way to do
this?

-1 should work for any unsigned type. I'm not certain that ~0 works
correctly for all possible integer representations; in any case,
-1 requires less thought.
Is including limits.h and using if->then statements with
sizeof(AEI_unit) be the most sure way?

This should work:

#define AEI_unit_max ((AEI_unit)-1)

and has the advantage of giving you a constant expression.

We can't tell from your description what's going wrong in your program.
If you post a complete compilable program that generates the "gibberish"
you're talking about, we can probably help.

(My best guess is that you're getting correct results but not printing
them correctly.)
 
S

Stefan Ram

Eyegor said:
typedef unsigned long AEI_unit;

Assuming the usual implementation of integers using two's
complement encoding (untested):

max = LOG2( sizeof( AEI_UNIT ) -( ( AEI_unit )( -1 )< 0 ))- 1;

, where »LOG2« needs to be defined to give the logarithm
with base 2.
 
S

Stefan Ram

Assuming the usual implementation of integers using two's
complement encoding (untested):
max = LOG2( sizeof( AEI_UNIT ) -( ( AEI_unit )( -1 )< 0 ))- 1;
, where »LOG2« needs to be defined to give the logarithm
with base 2.

Sorry, that should be EXP2 and give 2 raised to the power
of the argument.
 
E

Eyegor

Code is in these 3 files:
http://magicmrv.com/codes/AEI/aei.c
http://magicmrv.com/codes/AEI/aei.h
http://magicmrv.com/codes/AEI/main.c

if i define AEI_max as a constant, say 255 everything works great. If
I define AEI_max by
#define AEI_unit_max ((AEI_unit)-1)
the program works as long as there is no carry over from one digit to
the next. The value of AEI_max is used in that calculation.

Does 32 lcc differentiate between long and long long ints? My guess is
that when I assign 2^32-1 to AEI_unit_max which is a 32 bit int, the
compiler also assigns 32 bits to long long int type of AEIt type, even
though i am assuming its 64 bits, which is the type i use for carry,
so it ends up being overrun.

This is what I meant a cross compiler compliance. So basically if the
compiler does not support 64 bit ints; the AEIt should be 32 bit
unsigned int and AEI_unit should be a 16 bit unsigned int, so
AEI_unit_max should be the max of 16 bit number.

If i assign unsigned short to AEI_unit and unsigned long to AEIt so
there is no compiler decision abmiguity for 32/64 bit values, and the
values are forced to 16 and 32 bits everything seems to work even
using:

#define AEI_unit_max ((AEI_unit)-1)

so I guess the question becomes: how to force the compiler to use 32
and 64 bit variables if such are supported or to use 16 and 32 bit
values if 64 bit is not supported?

Not sure if there are any standard C flags/commands, but if there are
i'd love to know about them.
Thanks
 
K

Keith Thompson

Eyegor said:

That's several hundred lines of code, and I'm frankly unwilling to wade
through it to find your problem.

Create a *small* (say, up to 20 lines) test case that exhibits the
problem you're having.
if i define AEI_max as a constant, say 255 everything works great. If
I define AEI_max by
#define AEI_unit_max ((AEI_unit)-1)
the program works as long as there is no carry over from one digit to
the next. The value of AEI_max is used in that calculation.

In your aei.h file (I did take a quick look at it), you have:

#define AEI_unit_max (AEI_unit)-1

You're missing a set of parentheses; it needs to be:

#define AEI_unit_max ((AEI_unit)-1)

I don't know whether this is causing your problem. I'd have to
look at your calculation, which means you'd have to tell me what
it is, ideally by posting a small self-contained sample program.
(It's not unlikely that you'll solve the problem yourself in the
process of creating a small sample program.)

Upthread, you wrote:

I do not know in advance what the user will choose to use for
AEI_unit.

but AEI_unit and AEI_unit_max are defined in the same file. It looks
like *you're* defining them. If there's some mechanism for the user to
choose a type for AEI_unit, it's not reflected in your code. Is the
user expected to modify aei.h?
Does 32 lcc differentiate between long and long long ints? My guess is
that when I assign 2^32-1 to AEI_unit_max which is a 32 bit int, the
compiler also assigns 32 bits to long long int type of AEIt type, even
though i am assuming its 64 bits, which is the type i use for carry,
so it ends up being overrun.

By "32 lcc", I'm guessing you mean lcc-win32. I think the answer
is yes; long is 32 bits and long long is 64 bits. More generally,
long is guaranteed to be at least 32 bits, and long long is at
least 64 bits, for any conforming C99 implementation.
This is what I meant a cross compiler compliance. So basically if the
compiler does not support 64 bit ints; the AEIt should be 32 bit
unsigned int and AEI_unit should be a 16 bit unsigned int, so
AEI_unit_max should be the max of 16 bit number.

You're confusing the terms "int" and "integer". "int" is one specific
integer type; it can be 16, 32, or 64 bits, among other possibilities.
There are several other integer types, including short, long, and long
long, and their unsigned variations.

I think what you're saying is that you want AEIt to be a 32-bit
unsigned integer type, and AEI_unit to be a 16-bit unsigned
integer type.
If i assign unsigned short to AEI_unit and unsigned long to AEIt so
there is no compiler decision abmiguity for 32/64 bit values, and the
values are forced to 16 and 32 bits everything seems to work even
using:

#define AEI_unit_max ((AEI_unit)-1)

This is a misuse of the word "assign". I think you mean

If I define AEI_unit as unsigned short, and AEIt as unsigned long
...
so I guess the question becomes: how to force the compiler to use 32
and 64 bit variables if such are supported or to use 16 and 32 bit
values if 64 bit is not supported?

Take a look at <stdint.h>. If you need an unsigned type that's exactly
32 bits, use uint32_t. (If the implementation doesn't have such a type,
uint32_t won't exist.)

Note that *all* conforming C99 implementations must support at least
one unsigned integer type that's at least 64 bits wide.
 
I

Ike Naar

Assuming the usual implementation of integers using two's
complement encoding (untested):

max = LOG2( sizeof( AEI_UNIT ) -( ( AEI_unit )( -1 )< 0 ))- 1;

, where ?LOG2? needs to be defined to give the logarithm
with base 2.

Untested indeed ;-)
For AEI_UNIT=(unsigned long), UINT_MAX=4294967295, sizeof(unsigned long)=4,
that formula gives

max = LOG2(sizeof(AEI_UNIT) - ((AEI_unit)(-1) < 0)) - 1
= LOG2(4 - (4294967295 < 0)) - 1
= LOG2(4 - 0) - 1
= 2 - 1
= 1

Anyway, this topic was discussed at length in comp.lang.c just a couple of
weeks ago, and, if I remember correctly, a working solution was presented.
Check the archives.
 
E

Eric Sosman

Code is in these 3 files:
http://magicmrv.com/codes/AEI/aei.c
http://magicmrv.com/codes/AEI/aei.h
http://magicmrv.com/codes/AEI/main.c

if i define AEI_max as a constant, say 255 everything works great. If
I define AEI_max by
#define AEI_unit_max ((AEI_unit)-1)
the program works as long as there is no carry over from one digit to
the next. The value of AEI_max is used in that calculation.

Based on the aei.h file, the value is correct. AEI_unit turns
out to be `unsigned', which is synonymous with `unsigned int', so
the expression `(AEI_unit)-1' is the same as `(unsigned int)-1',
which is UINT_MAX.

You've shown the AEI_unit_max definition with more parentheses
than are actually present in your header file. Since `(unsigned int)'
has a fairly high precedence this won't make a difference in any
"normal" context, but it could lead to troubles with joke code like

AEI_unit_max["1234..."]

Still, it's, unsettling to discover that you can't even copy your own
code accurately. How in the world do you expect people to help you
if you lie to them about the circumstances of your problem?
 
S

Stefan Ram

Ike Naar said:
Anyway, this topic was discussed at length in comp.lang.c just a couple of
weeks ago, and, if I remember correctly, a working solution was presented.
Check the archives.

Thanks for the correction. I was trying to post too fast.
Sorry for the distraction. Here is another attempt.

The expression »rp2()« is intended to give the maximum
value of the type »T«.

#include <stdio.h>
#include <limits.h> /* CHAR_BIT */

#define T int

int ubits( ){ return sizeof(T)*CHAR_BIT; }
int issigned( ){ return (T)(-1)<0; }
int bits( ){ return ubits()-issigned(); }
unsigned long long rp2(){ return ~((~1ull)<<(bits()-1)); }
int main( void ){ printf( "%llu\n", rp2() ); }
 
K

Keith Thompson

Thanks for the correction. I was trying to post too fast.
Sorry for the distraction. Here is another attempt.

The expression »rp2()« is intended to give the maximum
value of the type »T«.

#include <stdio.h>
#include <limits.h> /* CHAR_BIT */

#define T int

int ubits( ){ return sizeof(T)*CHAR_BIT; }
int issigned( ){ return (T)(-1)<0; }
int bits( ){ return ubits()-issigned(); }
unsigned long long rp2(){ return ~((~1ull)<<(bits()-1)); }
int main( void ){ printf( "%llu\n", rp2() ); }

But if T is known to be an unsigned type (as it seems to be in this
case), ((T)-1) works (even in the presence of padding bits).
 

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,768
Messages
2,569,574
Members
45,048
Latest member
verona

Latest Threads

Top