Direct computation of integer limits in K&R2?

I

Ioannis Vranos

Ioannis said:
OK it is allowed, but is there any existing system where the value
ranges of signed int and unsigned int are different?


With "value ranges" above I mean the total values of each type.
 
U

user923005

Displaying the limits using the macros is easy: the C89 Standard mandates  
that the macros in <limits.h> must have the same type as an expression  
that is an object of the corresponding type converted according to the  
integral promotions (this excludes CHAR_BIT and MB_LEN_MAX). So this is  
perfectly reasonable:

    printf("char signed min = %d\n", SCHAR_MIN);
    printf("signed int min  = %d\n", INT_MIN);
    printf("signed int max  = %d\n", INT_MAX);
    /* etc. */

For calculating them, Tondo & Gimpel suggest this in "The C Answer Book":

    printf("signed char min    = %d\n", ~(char)((unsigned char) ~0 >> 1));
    printf("signed char max    = %d\n",  (char)((unsigned char) ~0 >> 1));
    printf("unsigned short min = %d\n", ~(short)((unsigned short) ~0 >> 1));
    printf("unsigned short max = %d\n",  (short)((unsigned short) ~0 >> 1));

and so on.

Obviously, I don't know to what peer review T&G's Answer Book was subject,  
but if their solutions are not correct, I would like to know.

It works for two's complement. Maybe that's just the trick:
You have to write a different solution for each possible number
format.
 
S

santosh

user923005 said:
It works for two's complement. Maybe that's just the trick:
You have to write a different solution for each possible number
format.

The question doesn't mention the word "portable" at all anywhere, so I
guess that a machine specific answer will count as a solution too.
 
C

CBFalconer

Harald said:
Yes, it can.


Of course. And any of the permissible implementation-defined
values of i will result in the intended behaviour.

I think you have a misinterpretation of 'implementaion-defined'.
This means that the action, on a particular implementation, is
defined. However that may well be "*** ABORT in line nnn, integer
overflow ***".
 
C

CBFalconer

Ioannis said:
.... snip ...

OK it is allowed, but is there any existing system where the value
ranges of signed int and unsigned int are different?

Yes. Consider a 16 bit system. INT_MAX is 32767. INT_MIN is
-32768 (or -32767). UINT_MAX is 65536 (UINT_MIN is naturally 0).
It is allowable to reserve the value that would represent -32768 to
indicate a special condition, such as uninitialized. Or, for a 1's
complement machine, the bit pattern for -0 is forbidden.
 
Y

ymuntyan

OK it is allowed, but is there any existing system where the value
ranges of signed int and unsigned int are different?

See above. You decide whether C rationale is lying or C committee
was lied to. I have no idea :)

Yevgen
 
Y

ymuntyan

The question doesn't mention the word "portable" at all anywhere, so I
guess that a machine specific answer will count as a solution too.

But then the following is a solution too:

int intmax = 2147483647;
int intmin = -2147483647 - 1;

Or, for "quite portable" version, look at glibc's limits.h.
And of course SCHAR_MAX = 127 :)

Yevgen
 
H

Harald van Dijk

I think you have a misinterpretation of 'implementaion-defined'. This
means that the action, on a particular implementation, is defined.
However that may well be "*** ABORT in line nnn, integer overflow ***".

If the result is implementation-defined, any result is permissible, but
there must be a result. If the behaviour is implementation-defined, any
behaviour (including, as you mention, exiting the program) is
permissible. In this case, the result is implementation-defined, and
exiting the program is not allowed.
 
B

Ben Bacarisse

user923005 said:
On Mar 14, 5:59 am, Martin <[email protected]> wrote:

It works for two's complement.

Are you sure? What happens when both signed and unsigned short (or
indeed, int in the "and so on" case) have the same number of value
bits? I think this is permitted and causes the wrong answer to be
printed, but my brain is already hurting from thinking about this
exercise.
Maybe that's just the trick:
You have to write a different solution for each possible number
format.

I hoped I could find a portable solution that way, but I drew a blank.
 
U

user923005

Are you sure?  What happens when both signed and unsigned short (or
indeed, int in the "and so on" case) have the same number of value
bits?  I think this is permitted and causes the wrong answer to be
printed, but my brain is already hurting from thinking about this
exercise.


I hoped I could find a portable solution that way, but I drew a blank.

You're right.
I think that every solution I have seen posted so far (including mine)
only works on a very limited subset of possible integer limit sets.
That makes this a very interesting exercise. And we have not even
touched the floating point yet.
 
Y

yalong

Hello all,

In K&R2 one exercise asks the reader to compute and print the limits for
the basic integer types. This is trivial for unsigned types. But is it
possible for signed types without invoking undefined behaviour
triggered by overflow? Remember that the constants in limits.h cannot
be used.
Hi santosh

Maybe you could take this book for reference:
the c answer book 2Edtion by Clovis L. Tondo & Scott E. Gimpel

And,there is a way about signed char on that book
printf("signed char min = %d\n", -(char)((unsigned char) ~0 >> 1));

but i think it should be that
printf("signed char min = %d\n", -1 -(char)((unsigned char) ~0 >> 1));
maybe it's a little mistake of press :)

There aren't solutions about floats, i think the other book
Computer Systems A Programmer's Perspective by Randal E. Bryant &
David O'Hallaron
of CMU could help.

Good luck!
yalong
 
M

Martin

Maybe you could take this book for reference:
the c answer book 2Edtion by Clovis L. Tondo & Scott E. Gimpel

And,there is a way about signed char on that book
printf("signed char min = %d\n", -(char)((unsigned char) ~0 >> 1));

but i think it should be that
printf("signed char min = %d\n", -1 -(char)((unsigned char) ~0 >> 1));
maybe it's a little mistake of press :)

I think you've misread the symbol ~ as -. In another message in this
thread I posted this, an extract of T&G's solution:

printf("signed char min = %d\n", ~(char)((unsigned char) ~0 >> 1));
printf("signed char max = %d\n", (char)((unsigned char) ~0 >> 1));
printf("unsigned short min = %d\n", ~(short)((unsigned short) ~0 >> 1));
printf("unsigned short max = %d\n", (short)((unsigned short) ~0 >> 1));
 
Y

yalong

I think you've misread the symbol ~ as -. In another message in this
thread I posted this, an extract of T&G's solution:

printf("signed char min = %d\n", ~(char)((unsigned char) ~0 >> 1));
printf("signed char max = %d\n", (char)((unsigned char) ~0 >> 1));
printf("unsigned short min = %d\n", ~(short)((unsigned short) ~0 >> 1));
printf("unsigned short max = %d\n", (short)((unsigned short) ~0 >> 1));

hi Martin,

Thanks about that. I got a misprint book of my language vision.
Both of them get the right value, maybe it's little different in
running time.

yalong
 
P

Peter Nilsson

yalong said:
Hi santosh

Maybe you could take this book for reference:
the c answer book 2Edtion by Clovis L. Tondo & Scott E. Gimpel

Or maybe you shouldn't.
And,there is a way about signed char on that book
printf("signed char min = %d\n",
-(char)((unsigned char) ~0 >> 1));

~0 may be a trap representation on sign-magnitude machines.
The (unsigned char) ~0 is much better stated as (unsigned
char) -1, which yields UCHAR_MAX portably. But the single
right shifting of that need not yield SCHAR_MAX.[*] The
further negation of that need not yield SCHAR_MIN.

[*] The standard doesn't preclude UCHAR_MAX == 65535 and
SCHAR_MAX == 127.
but i think it should be that
printf("signed char min = %d\n",
-1 -(char)((unsigned char) ~0 >> 1));

Excellent. All the flaws above and one more. ;)
maybe it's a little mistake of press :)

The cast conversion to _plain_ char is certainly a mistake,
even if inconsequencial in context. But I doubt it's a
printing error.
 
R

rpgfan3233

Hi santosh
Maybe you could take this book for reference:
the c answer book 2Edtion by Clovis L. Tondo & Scott E. Gimpel

Or maybe you shouldn't.
And,there is a way about signed char on that book
printf("signed char min = %d\n",
 -(char)((unsigned char) ~0 >> 1));

~0 may be a trap representation on sign-magnitude machines.
The (unsigned char) ~0 is much better stated as (unsigned
char) -1, which yields UCHAR_MAX portably. But the single
right shifting of that need not yield SCHAR_MAX.[*] The
further negation of that need not yield SCHAR_MIN.

[*] The standard doesn't preclude UCHAR_MAX == 65535 and
SCHAR_MAX == 127.
but i think it should be that
printf("signed char min = %d\n",
  -1 -(char)((unsigned char) ~0 >> 1));

Excellent. All the flaws above and one more. ;)
maybe it's a little mistake of press :)

The cast conversion to _plain_ char is certainly a mistake,
even if inconsequencial in context. But I doubt it's a
printing error.

This seems rather simple to me, but perhaps it is just my
inexperience. Here is a solution that works on all of the platforms
I've worked with, but I haven't worked with ALL computers:
unsigned long long ULL_MAX = (unsigned long long)(-1LL);
unsigned long long ULL_MIN = 0ULL; //automatically known because the
smallest unsigned value is 0
signed long long SLL_MAX = (signed long long)(ULL_MAX >> 1);
signed long long SLL_MIN = SLL_MAX + 1;

It is also somewhat easily adaptable. Just change the types from long
long to another integral type!
 
R

Richard Heathfield

rpgfan3233 said:

This seems rather simple to me, but perhaps it is just my
inexperience. Here is a solution that works on all of the platforms
I've worked with, but I haven't worked with ALL computers:
unsigned long long ULL_MAX = (unsigned long long)(-1LL);
unsigned long long ULL_MIN = 0ULL; //automatically known because the
smallest unsigned value is 0
signed long long SLL_MAX = (signed long long)(ULL_MAX >> 1);
signed long long SLL_MIN = SLL_MAX + 1;

Presumably you mean SLL_MIN = -SLL_MAX - 1;

Unfortunately, this last one can break on sign-and-magnitude
implementations. Worse, as we were reminded quite recently, C doesn't
forbid implementations from setting U<int_type>_MAX equal to
<int_type>_MAX.
 
K

Keith Thompson

CBFalconer said:
I think you have a misinterpretation of 'implementaion-defined'.
This means that the action, on a particular implementation, is
defined. However that may well be "*** ABORT in line nnn, integer
overflow ***".

Interestingly, the definition of "implementation-defined behavior"
changed from C90 to C99.

The C90 standard says:

implementation-defined behavior

behavior, for a correct program construct and correct data, that
depends on the characteristics of the implementation and that each
implementation shall document

C99 says:

unspecified behavior

use of an unspecified value, or other behavior where this
International Standard provides two or more possibilities and
imposes no further requirements on which is chosen in any instance

implementation-defined behavior

unspecified behavior where each implementation documents how the
choice is made

So C99 requires the actual behavior to match one of the limited set of
choices allowed by the standard, whereas C90 doesn't seem to impose
such a limitation. But I *think* (though I'm not sure) that it
amounts to the same thing. I think that, for each instance of
implementation-defined behavior, the C90 standard restricts the actual
behavior to a limited number of choices. Thus the limitation is
expressed for each instance throughout the standard, whereas in C99
this is reinforced in the definition.
 
K

Keith Thompson

CBFalconer said:
Yes. Consider a 16 bit system. INT_MAX is 32767. INT_MIN is
-32768 (or -32767). UINT_MAX is 65536 (UINT_MIN is naturally 0).

Or it would be 0 if it existed.
It is allowable to reserve the value that would represent -32768 to
indicate a special condition, such as uninitialized. Or, for a 1's
complement machine, the bit pattern for -0 is forbidden.

How does this answer the question? You've demonstrated that it's
allowed, which he already knows. The question is whether they're
different on any existing system. (The really interestion question,
IMHO, is "if so, which one?")
 
B

Ben Bacarisse

Peter Nilsson said:
yalong <[email protected]> wrote:

~0 may be a trap representation on sign-magnitude machines.

Did you mean ones' complement? I thought sign bit = 1 and all value
bits 1 had to be well-defined on sign-magnitude systems.

On ones' complement systems, ~0 is either negative zero (and the
conversion to unsigned char will produce 0) or it is a trap
representation. The above code is definitely useless on such a
system.
 

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,755
Messages
2,569,536
Members
45,014
Latest member
BiancaFix3

Latest Threads

Top