"Pedro Izecksohn" <[EMAIL PROTECTED]> wrote:
>
> For peternilsson42:
> 
> I was not clear and you did not read message 68798.
> 
> http://tech.groups.yahoo.com/group/c-prog/message/68798

That post contained detail missing from your original post.
However, it did not contain detail which explained why you
where confused.

> To clarify:
> 
> That code I compiled on two independent compilers. On
> both compilers:
> 
> USHRT_MAX is 0xffff
> UINT_MAX is 0xffffffff
> ULLONG_MAX is 0xffffffffffffffff
> 
> > For integers with a 'rank' less than int, if the
> > range of the integer type fits into the range of
> > int, then that type will promote to int, if it
> > is promoted. If the range won't fit into an int,
> > it will be promoted to an unsigned int.
> 
> It shows that you read the standard.

It also explains the results you received.

> > Consider the test: (-1 < (unsigned short) 1)
> > 
> > Whilst intuitively it should always be true, there
> > are many implementations where it is false!
> 
> The unsigned short value 1 fits into an int and -1
> is an int, so, according to the standard this test
> must be true.

On your machine perhaps, but there are any number of
machines where USHRT_MAX > INT_MAX. [DSPs seem to be
more common than desktop PC's, but when I started C,
most high end systems did not bother with 16-bit types.
Everything was either 8-bit, or at least 32-bit.]

> > > > a = -1;
> 
> I changed this line in message 68798 to:
> 
> a = USHRT_MAX;

So you made absolutely _no_ change to the semantics of
that assignment!

> > Here's a table of what a will promote to, and the
> > type of a * a, dependant on the maximum values of
> > unsigned short, int and unsigned int:
> 
> I'm sorry I was not sufficiently clear.

Your post didn't need to be. I was trying to explain
the language, but using three examples as illustration.
You seem to be only interested in one class of machine.
No matter... ;-)

> > Unsigned integers do not get sign-extended when
> > promoted to wider unsigned integer types. Why?
> > Because there is no sign to extend!
> 
> This is exactly how I thought before I saw two
> independent compilers producing the binaries that
> result that result.

I don't understand that sentence. No conforming
implementation can exhibit sign extension for an
unsigned integer type since no unsigned integer
type has a sign bit.

> > First, you believe promotion works from the
> > outside in. In other words, the type of the
> > variable you're assigning to will influence
> > the types and promotion of the expression on
> > the right hand side. They won't. It works from
> > the inside out.
> 
> No. I used unsigned short int and unsigned long
> long int because the original calculation needs
> them, because the result of the original
> calculation may not fit inside an unsigned int.

That's fine, but it doesn't explain why you found
the results confusing. Misunderstanding promotion
explains it perfectly. :-)

> The original calculation is more complex than a
> multiplication of two integers.

Well, if you're ready, you might like to post the
more complicated example.

> > Secondly, you've probably been confused by
> > 'hex' output
> 
> No. I used hexadecimal representation because
> these extreme values are best represented in
> hexadecimal.

I didn't mean you couldn't read hex, I meant that
many people see hex, they have a conditioned response
to believe that the hex value _is_ the representation,
as well as, the value.

> I hope that you answer my question, that is explicit
> in my other message.

My previous message explains precisely why you received
the output you received. But instead of explaining it
in terms of one specific machine, I tried to explain
the language itself, showing three possible implementations,
one of which appears to match the machine you're using.

> My personal opinion is that the two independent compilers
> I used are buggy,

I've actually demonstrated why they're not.

> but I want another opinion before reporting this bug
> to two independent developers.

You would look very foolish if you reported this as a
bug.

But, for the sake of trying to make my post a little
clearer, let's suppose we have an implementation that
you describe above...

  USHRT_MAX is 0xffff
  UINT_MAX is 0xffffffff
  ULLONG_MAX is 0xffffffffffffffff

This isn't enough to fully explain what's going on so
let me add the reasonable assumption:

  INT_MAX is 0x7FFFFFFF

Now, let's start...

  unsigned short int a;
  unsigned long long int b, c;

All good. [BTW, many people tend not to bother with 'int'
when using unsigned types.]

  a = USHRT_MAX;

This will assign a the value 0xFFFF. So will a = -1 on
your machine as (USHRT_MAX plus 1) plus (minus 1) is
USHRT_MAX.

  b = (a*a);

Forget about "b =" and the parentheses. The first detail
is a * a. Now since a has lower rank than int, it is
subject to integral promotion in that sub-expression.
Since USHRT_MAX < INT_MAX, it promotes to int. Thus,
the statement (on this particular machine) is the same
as:

  b = (65535 * 65535);

Now 65535 * 65535 has the _mathematical_ value of
4294836225. That value is too large to be represented
as an int on your machine. The behaviour of your program
is undefined, so if this is what your real code actually
does, it should be rewritten. But let's continue.

On many machines, overflow of a two's complement value
will simply yield the result as if the truncated binary
representation of the result where placed directly into
an int object. So it's likely that the notional value
4294836225 will actually be -131071.[*]

Thus your statement becomes...

  b = (-131071);

Or more simply...

  b = -131071;

Now, when you assign a value to an unsigned integer, it
will be reduced modulo one more than the maximum value 
of that type. Hence, it will be reduced modulo (in hex)
0x10000000000000000 (i.e. ULLONG_MAX plus 1). Now, that
value is 18446744073709420545 (or 0xFFFFFFFFFFFE0001.)

That explains what you see when you print b.

So we move on to...

  c = ((unsigned int)a*(unsigned int)a);

What you have is...

  c = (A * A); /* where A is ((unsigned) a) */

You've directly converted the value of a to an unsigned
int. Since this preserves value, A also has the value
0xFFFF, only _now_ it is an unsigned int.

When you multiply A by itself, again you get the
mathematical result 4294836225. This result _is_ in the
range of unsigned int on your system, so the result
stays as 0xFFFE0001.

Now this value is assigned to c. But unsigned long long
is (indeed must be) wide enough to hold any value of an
unsigned int. So it's as if you had written...

  c = 0xFFFE0001;

It should now come as no surprise that this is the value
you see when you print c.

There is no reason to think that b's value should be
truncated to 0xFFFE0001, nor that c's value should be
extended to 0xFFFFFFFFFFFE0001.

So which do you think, and why do you think that? Or,
do you think different values should be displayed?

--
* It's as if you had written...
  unsigned tmp = 4294836225;
  (* (int *) &tmp) 

-- 
Peter

Reply via email to