Direct computation of integer limits in K&R2?

R

Richard Heathfield

CBFalconer said:
Totally unnecessary. All those integral max values are specified
in <limits.h>. That's why.

Is it, then, your claim that doing K&R exercises is a waste of time?
 
U

user923005

CBFalconer said:




Is it, then, your claim that doing K&R exercises is a waste of time?

I think it is incredibly instructive simply understanding how
difficult it is.

I am not convinced one way or another if it is possible or not.
The unsigned types are (of course) easy. But the semi-solutions I
posted definitely do not work on some platforms (which may or may not
be hypothetical) because they assume that you can assign a larger
integer type to a smaller one and that there will never be a trap
(along with a few other chummy assumptions). So I think that a fully
portable solution that can calculate the values for both signed
integer and also floating point will be a very interesting achivement.
 
I

Ioannis Vranos

santosh said:
Perhaps, but that's a bit of a cheat, IMO.

In any case how do you propose to use the min. and max. values in
limits.h to work out the integer representation?


Well we can see if INT_MIN==-INT_MAX-1 or not. And then use my code if
this is the case, for the else part perhaps you may provide some
solution. :)
 
C

CBFalconer

Richard said:
CBFalconer said:

Is it, then, your claim that doing K&R exercises is a waste of time?

I believe (K&R is lost in the mess) the original problem didn't ban
limits.h
 
C

CBFalconer

Ioannis said:
.... snip ...

Well we can see if INT_MIN==-INT_MAX-1 or not. And then use my
code if this is the case, for the else part perhaps you may
provide some solution. :)

If not, you have discovered undefined behaviour.
 
B

Ben Bacarisse

CBFalconer said:
I believe (K&R is lost in the mess) the original problem didn't ban
limits.h

No, but it suggests trying to do it by direct calculation as well. It
is from that suggestion that the whole thread grew.
 
P

Peter Nilsson

CBFalconer said:
Ark said:
Peter said:
Unfortunately, many implementations are somewhat
inconsistent. Consider...

  #include <limits.h>
  #include <stdio.h>

  int main(void) {
    printf("ULONG_MAX = %lu\n", ULONG_MAX);

  #if -1 == -1ul
    puts("-1 == -1ul [pre]");
  #endif

    if (-1 == -1ul)
      puts("-1 == -1ul");

  #if 4294967295 == -1ul
    puts("4294967295 == -1ul [pre]");
  #endif

    if (4294967295 == -1ul)
      puts("4294967295 == -1ul");
    return 0;
  }

The output for me using delorie gcc 4.2.1 with -ansi
-pedantic is...

  ULONG_MAX = 4294967295
  -1 == -1ul [pre]
  -1 == -1ul
  4294967295 == -1ul

As you can see, there is a discrepancy between the way
that preprocessor arithmetic is evaluated. Fact is,
gcc is not the only compiler to show problems.

What's wrong with that,

It violates the standard in the cited section that you
snipped...

C89 draft 3.8.1
...The resulting tokens comprise the controlling constant
expression which is evaluated according to the rules of
$3.4 using arithmetic that has at least the ranges
specified in $2.2.4.2, except that int and unsigned int
act as if they have the same representation as,
respectively, long and unsigned long. ...

The output should have included...

4294967295 == -1ul [pre]
remembering that (for gcc, on xx86's) a
long is defined to be identical to an int.

They're not compatible types, but if you mean they
have the same representation then I don't see how
that's relevant.
 
I

Ioannis Vranos

santosh said:
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.


C90:

The original exercise text as provided by Richard Heathfield is:

Exercise 2-1. Write a program to determine the ranges of char, short,
int, and long, both signed and unsigned, by printing appropriate values
from standard headers and by direct computation. Harder if you compute
them: determine the ranges of the various floating-point types.


Any ideas?


I think the text gives us space, in the signed int case to see if
INT_MIN== -INT_MAX-1 or INT_MIN== -INT_MAX, and act accordingly with
unsigned int:


#include <stdio.h>
#include <limits.h>


int main()
{
unsigned x= -1;

int INTMIN, INTMAX;

printf("INT_MIN= %d, INT_MAX= %d\n", INT_MIN, INT_MAX);

if (INT_MIN== -INT_MAX -1)
{
INTMAX=x /2;

INTMIN= -INTMAX -1;
}

else
{
INTMAX=x /2;

INTMIN= -INTMAX;

}


printf("INTMIN= %d, INTMAX= %d\n", INTMIN, INTMAX);


return 0;
}



Probably this is a stupid solution. But what can we take for granted,
"by printing appropriate values from standard headers"?
 
U

user923005

C90:

The original exercise text as provided by Richard Heathfield is:

Exercise 2-1. Write a program to determine the ranges of char, short,
int, and long, both signed and unsigned, by printing appropriate values
from standard headers and by direct computation. Harder if you compute
them: determine the ranges of the various floating-point types.

Any ideas?

I think the text gives us space, in the signed int case to see if
INT_MIN== -INT_MAX-1 or INT_MIN== -INT_MAX, and act accordingly with
unsigned int:

#include <stdio.h>
#include <limits.h>

int main()
{
     unsigned x= -1;

     int INTMIN, INTMAX;

     printf("INT_MIN= %d, INT_MAX= %d\n", INT_MIN, INT_MAX);

     if (INT_MIN== -INT_MAX -1)
     {
            INTMAX=x /2;

            INTMIN= -INTMAX -1;
     }

     else
     {
            INTMAX=x /2;

            INTMIN= -INTMAX;

     }

     printf("INTMIN= %d, INTMAX= %d\n", INTMIN, INTMAX);

     return 0;

}

Probably this is a stupid solution. But what can we take for granted,
"by printing appropriate values from standard headers"?

This probably works on many platforms, but a really interesting
solution would be one that works on every platform.
 
Y

ymuntyan

C90:

The original exercise text as provided by Richard Heathfield is:

Exercise 2-1. Write a program to determine the ranges of char, short,
int, and long, both signed and unsigned, by printing appropriate values
from standard headers and by direct computation. Harder if you compute
them: determine the ranges of the various floating-point types.

Any ideas?

I think the text gives us space, in the signed int case to see if
INT_MIN== -INT_MAX-1 or INT_MIN== -INT_MAX, and act accordingly with
unsigned int:

#include <stdio.h>
#include <limits.h>

int main()
{
unsigned x= -1;

int INTMIN, INTMAX;

printf("INT_MIN= %d, INT_MAX= %d\n", INT_MIN, INT_MAX);

if (INT_MIN== -INT_MAX -1)
{
INTMAX=x /2;

INTMIN= -INTMAX -1;
}

else
{
INTMAX=x /2;

INTMIN= -INTMAX;

}

printf("INTMIN= %d, INTMAX= %d\n", INTMIN, INTMAX);

return 0;

}

Probably this is a stupid solution. But what can we take for granted,
"by printing appropriate values from standard headers"?

What did you do in this code? Did you compute INT_MAX and
INT_MIN using INT_MAX and INT_MIN? Note that (unsigned)-1 / 2
may be out of range of int (by the way, C99 rationale says
that the committee was told that there actually was an
implementation where UINT_MAX + 1 was *four* times INT_MAX + 1).

Yevgen
 
M

Micah Cowan

Richard Heathfield said:
Peter Nilsson said:


I don't think it can. "For each of the signed integer types, there is a
corresponding (but different) unsigned integer type (designated with the
keyword unsigned) that uses the same amount of storage (including sign
information) and has the same alignment requirements. The range of
nonnegative values of a signed integer type is a subrange of the
corresponding unsigned integer type, and the representation of the same
value in each type is the same." So for UINT_MAX to be == INT_MAX, ints
would need to squeeze twice as many values into the same number of bits as
unsigned ints.

Why is that a problem? The standard allows for representations in
which the bit that corresponds to a sign bit for the signed integer,
is a padding bit in the unsigned integer (an equal number of value
bits between int and unsigned int is specifically allowed).
 
R

Richard Heathfield

Ioannis Vranos said:

The original exercise text as provided by Richard Heathfield is:

Exercise 2-1. Write a program...

Just a nit. It was Brian Kernighan who originally wrote that exercise, not
me. I only quoted it!
 
R

Richard Heathfield

CBFalconer said:
It is the last draft of C99 before publication, and the last
version available in text form.

He doesn't want one. In case you hadn't noticed, he's teaching a C90/C95
course.
 
M

Martin

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.
 
I

Ioannis Vranos

What did you do in this code? Did you compute INT_MAX and
INT_MIN using INT_MAX and INT_MIN? Note that (unsigned)-1 / 2
may be out of range of int (by the way, C99 rationale says
that the committee was told that there actually was an
implementation where UINT_MAX + 1 was *four* times INT_MAX + 1).


How can this happen given that sizeof(int)== sizeof(unsigned it)?
 
M

Micah Cowan

Ioannis Vranos said:
How can this happen given that sizeof(int)== sizeof(unsigned it)?

Not all the bits in int are required to be value or sign bits (some
may be padding bits). And some of the bits that are value bits in an
unsigned int are allowed to be padding bits in the signed int.
 
B

Ben Bacarisse

Martin said:
Displaying the limits using the macros is easy:

Agreed, so I've snipped...
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.

These can't work on sign & magnitude systems since the min. and max.
values aren't the (bit-wise) complement of each other. On ones'
complement systems, (unsigned char)~0 should be zero, I think -- the
conversion is based on the value of ~0 not the bit pattern. On twos'
complement systems, it is possible that both signed and unsigned short
have the same number of value bits. On such a system, the expression
will print too small a maximum.
 
H

Harald van Dijk

This CAN'T work everywhere.

Yes, it can.
The u = -1 statement is legal, and results
in UINT_MAX value. However the first i = u statement always overruns
the INT_MAX value for i, unless the system has INT_MAX defined to be
equal to UINT_MAX. Very rare. So the result of that statement is
implementation defined.

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

As long as u > INT_MAX, then i cannot possibly be equal to u. It could be
negative, or it could be zero, or it could be positive. If it is
negative, then the comparison to 0 continues the loop. If it is not
negative, then i != u, because i <= INT_MAX, and u > INT_MAX, so the loop
continues.

As soon as u <= INT_MAX, then i must be equal to u, so the loop exits.
 
I

Ioannis Vranos

Micah said:
Not all the bits in int are required to be value or sign bits (some
may be padding bits). And some of the bits that are value bits in an
unsigned int are allowed to be padding bits in the signed int.

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

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,769
Messages
2,569,578
Members
45,052
Latest member
LucyCarper

Latest Threads

Top