Topic: integral conversions bug


Author: "Alan M. Feldstein" <alan.feldstein@computer.org>
Date: Mon, 5 Jun 2006 21:36:17 CST
Raw View
kuyper@wizard.net wrote:

>"Alan M. Feldstein" wrote:
>
>
>>#include <cassert>
>>
>>int main()
>>{
>> unsigned long bundle_loc_mask = ( unsigned long )0 | -1;
>> assert( bundle_loc_mask == 0x00000000ffffffffUL );
>>
>> return 0;
>>
>>}
>>
>>With the LP64 data model and INCITS/ISO/IEC 14882-2003, I expect the
>>assertion to be true. On Sun Studio 11 however, the assertion fails,
>>leading me to the conclusion that that is a nonconforming compiler.
>>
>>"Integral conversions" are covered int Section 4.7 of the C++ Standard.
>>My goal is a discussion about the correctness of my interpretation of
>>the C++ Standard. The discussion began at
>>http://forum.sun.com/jive/thread.jspa?threadID=96796&tstart=0
>>
>>1 is an integer literal. - is a unary operator.
>>
>>According to Section 2.13.1 paragraph 2, "If it is decimal and has no
>>suffix, it has the first of these types in which its value can be
>>represented: int, long int;" so 1 is an int.
>>
>>According to Section 5.3.1 paragraph 7, "The operand of the unary -
>>operator shall have arithmetic or enumeration type and the result is the
>>negation of its operand. Integral promotion is performed on integral or
>>enumeration operands. The negative of an unsigned quantity is computed
>>by subtracting its value from 2^n , where n is the number of bits in the
>>promoted operand. The type of the result is the type of the promoted
>>operand." The operand has arithmetic type. Integral promotion has no
>>effect. The negative of 1 is computed by subtracting its value from 2^32
>>, resulting in 0xffffffff. (I have started a separate thread "integer
>>literals bug" for debating what the literal
>>0xffffffff
>>is.)
>>
>>
>
>What you've written above would be correct for -1U (assuming that
>UINT_MAX is 0xffffffff), since 1U is an unsigned value. However, as you
>yourself have pointed out above, the literal 1 has a type of int, not
>unsigned int. Therefore, the result of the unary minus operation is an
>int with a value of -1.
>
>I gather from looking at the sun web site that you referred us to, that
>you've been confused by the fact that -1, for a signed integer using 16
>
32

>bit 2's complement form, is represented by the same bit pattern that
>would, if interpreted as an unsigned integer, represent 0xffffffff.
>While true, that's irrelevant. The C rules for the handling of a signed
>int value of -1 are quite different from the rules for the handling of
>an unsigned int value of 0xffffffff. They compare equal when UINT_MAX
>is 0xffffffff, because 0xffffffff is a literal with a type of unsigned
>int, and the comparison therefore requires conversion of -1 to unsigned
>int type, which will give UINT_MAX. However, there are many operations
>(conversion to unsigned long being one of them) where the two different
>values will give very different answers, despite being represented by
>the same bit pattern.
>
>
>
>>Now we look at the left operand of the bitwise inclusive OR and see that
>>we need promotion of the right operand.
>>(unsigned long)0xffffffff
>>The implicit conversion is governed by the rules for integral conversion
>>in the Standard (Section 4.7). "If the destination type is unsigned, the
>>resulting value is the least unsigned integer congruent to the source
>>integer (modulo 2^n where n is the number of bits used to represent the
>>unsigned type)." For this conversion, n is 64.
>>
>>
>
>And therefore, the conversion of -1 to unsigned long involves
>(conceptually) adding 2^n to  -1 as many times as needed to produce a
>positive value. In this case, it only needs to be done once, giving
>ULONG_MAX.
>
>---
>[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
>[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
>[              --- Please see the FAQ before posting. ---               ]
>[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]
>
>
>
I realized the weakness in my argument when I wrote it: "The negative of
an unsigned quantity is computed ...", knowing that the literal 1 has a
type of int (a signed integer type) even though it is a positive number.

Nevertheless, "the result [of application of the unary operator] is the
negation of its operand." The type of the result is int.

So we have the negation of 1, which I must admit is /not/ an unsigned
quantity. Therefore, the rule I cited does not apply. I have to agree
with you about the value and type of the expression to the right of the
bitwise exclusive OR operator.

Now we look at the left operand of the bitwise inclusive OR and see that
we need promotion of the right operand.
(unsigned long)-1
The implicit conversion is governed by the rules for integral conversion
in the Standard (Section 4.7). "If the destination type is unsigned, the
resulting value is the least unsigned integer congruent to the source
integer (modulo 2^n where n is the number of bits used to represent the
unsigned type)." For this conversion, n is 64.

By definition,
resultingValue     -1 (mod 18446744073709551616)
if
18446744073709551616     (resultingValue - (-1))

resultingValue is the least unsigned integer for which the above
definition is satisfied. In the LP64 data model, we have an unsigned
long if the value is between 0 and 18446744073709551615 inclusive.

resultingValue = 18446744073709551615

In other words, I agree with you completely.
--

Alan Feldstein

http://www.alanfeldstein.com/

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: alan.feldstein@computer.org ("Alan M. Feldstein")
Date: Thu, 1 Jun 2006 14:34:01 GMT
Raw View
#include <cassert>

int main()
{
 unsigned long bundle_loc_mask = ( unsigned long )0 | -1;
 assert( bundle_loc_mask == 0x00000000ffffffffUL );

 return 0;

}

With the LP64 data model and INCITS/ISO/IEC 14882-2003, I expect the
assertion to be true. On Sun Studio 11 however, the assertion fails,
leading me to the conclusion that that is a nonconforming compiler.

"Integral conversions" are covered int Section 4.7 of the C++ Standard.
My goal is a discussion about the correctness of my interpretation of
the C++ Standard. The discussion began at
http://forum.sun.com/jive/thread.jspa?threadID=96796&tstart=0

1 is an integer literal. - is a unary operator.

According to Section 2.13.1 paragraph 2, "If it is decimal and has no
suffix, it has the first of these types in which its value can be
represented: int, long int;" so 1 is an int.

According to Section 5.3.1 paragraph 7, "The operand of the unary -
operator shall have arithmetic or enumeration type and the result is the
negation of its operand. Integral promotion is performed on integral or
enumeration operands. The negative of an unsigned quantity is computed
by subtracting its value from 2^n , where n is the number of bits in the
promoted operand. The type of the result is the type of the promoted
operand." The operand has arithmetic type. Integral promotion has no
effect. The negative of 1 is computed by subtracting its value from 2^32
, resulting in 0xffffffff. (I have started a separate thread "integer
literals bug" for debating what the literal
0xffffffff
is.)

Now we look at the left operand of the bitwise inclusive OR and see that
we need promotion of the right operand.
(unsigned long)0xffffffff
The implicit conversion is governed by the rules for integral conversion
in the Standard (Section 4.7). "If the destination type is unsigned, the
resulting value is the least unsigned integer congruent to the source
integer (modulo 2^n where n is the number of bits used to represent the
unsigned type)." For this conversion, n is 64.

The resulting value is the least unsigned integer congruent to
0xffffffff
modulo
0x10000000000000000
Congruence requires that
resultingValue % 0x10000000000000000 == 0xffffffff % 0x10000000000000000
The least unsigned long for which congruence is satisfied is
0x00000000ffffffff
--

Alan Feldstein

http://www.alanfeldstein.com/

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: kuyper@wizard.net
Date: Thu, 1 Jun 2006 13:35:14 CST
Raw View
"Alan M. Feldstein" wrote:
> #include <cassert>
>
> int main()
> {
>  unsigned long bundle_loc_mask = ( unsigned long )0 | -1;
>  assert( bundle_loc_mask == 0x00000000ffffffffUL );
>
>  return 0;
>
> }
>
> With the LP64 data model and INCITS/ISO/IEC 14882-2003, I expect the
> assertion to be true. On Sun Studio 11 however, the assertion fails,
> leading me to the conclusion that that is a nonconforming compiler.
>
> "Integral conversions" are covered int Section 4.7 of the C++ Standard.
> My goal is a discussion about the correctness of my interpretation of
> the C++ Standard. The discussion began at
> http://forum.sun.com/jive/thread.jspa?threadID=96796&tstart=0
>
> 1 is an integer literal. - is a unary operator.
>
> According to Section 2.13.1 paragraph 2, "If it is decimal and has no
> suffix, it has the first of these types in which its value can be
> represented: int, long int;" so 1 is an int.
>
> According to Section 5.3.1 paragraph 7, "The operand of the unary -
> operator shall have arithmetic or enumeration type and the result is the
> negation of its operand. Integral promotion is performed on integral or
> enumeration operands. The negative of an unsigned quantity is computed
> by subtracting its value from 2^n , where n is the number of bits in the
> promoted operand. The type of the result is the type of the promoted
> operand." The operand has arithmetic type. Integral promotion has no
> effect. The negative of 1 is computed by subtracting its value from 2^32
> , resulting in 0xffffffff. (I have started a separate thread "integer
> literals bug" for debating what the literal
> 0xffffffff
> is.)

What you've written above would be correct for -1U (assuming that
UINT_MAX is 0xffffffff), since 1U is an unsigned value. However, as you
yourself have pointed out above, the literal 1 has a type of int, not
unsigned int. Therefore, the result of the unary minus operation is an
int with a value of -1.

I gather from looking at the sun web site that you referred us to, that
you've been confused by the fact that -1, for a signed integer using 16
bit 2's complement form, is represented by the same bit pattern that
would, if interpreted as an unsigned integer, represent 0xffffffff.
While true, that's irrelevant. The C rules for the handling of a signed
int value of -1 are quite different from the rules for the handling of
an unsigned int value of 0xffffffff. They compare equal when UINT_MAX
is 0xffffffff, because 0xffffffff is a literal with a type of unsigned
int, and the comparison therefore requires conversion of -1 to unsigned
int type, which will give UINT_MAX. However, there are many operations
(conversion to unsigned long being one of them) where the two different
values will give very different answers, despite being represented by
the same bit pattern.

> Now we look at the left operand of the bitwise inclusive OR and see that
> we need promotion of the right operand.
> (unsigned long)0xffffffff
> The implicit conversion is governed by the rules for integral conversion
> in the Standard (Section 4.7). "If the destination type is unsigned, the
> resulting value is the least unsigned integer congruent to the source
> integer (modulo 2^n where n is the number of bits used to represent the
> unsigned type)." For this conversion, n is 64.

And therefore, the conversion of -1 to unsigned long involves
(conceptually) adding 2^n to  -1 as many times as needed to produce a
positive value. In this case, it only needs to be done once, giving
ULONG_MAX.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Bart van Ingen Schenau <bart@ingen.ddns.info>
Date: Thu, 1 Jun 2006 15:20:01 CST
Raw View
Alan M. Feldstein wrote:

> #include <cassert>
>
> int main()
> {
>  unsigned long bundle_loc_mask = ( unsigned long )0 | -1;
>  assert( bundle_loc_mask == 0x00000000ffffffffUL );
>
>  return 0;
>
> }
>
> With the LP64 data model and INCITS/ISO/IEC 14882-2003, I expect the
> assertion to be true. On Sun Studio 11 however, the assertion fails,
> leading me to the conclusion that that is a nonconforming compiler.

The results lead me to the conclusion that the compiler is conforming,
and that your understanding is not.

>
> "Integral conversions" are covered int Section 4.7 of the C++
> Standard. My goal is a discussion about the correctness of my
> interpretation of the C++ Standard. The discussion began at
> http://forum.sun.com/jive/thread.jspa?threadID=96796&tstart=0
>
> 1 is an integer literal. - is a unary operator.
>
> According to Section 2.13.1 paragraph 2, "If it is decimal and has no
> suffix, it has the first of these types in which its value can be
> represented: int, long int;" so 1 is an int.

That is right. And remember that the type 'int' stores a _signed_
quantity.

>
> According to Section 5.3.1 paragraph 7, "The operand of the unary -
> operator shall have arithmetic or enumeration type and the result is
> the negation of its operand. Integral promotion is performed on
> integral or enumeration operands. The negative of an unsigned quantity
> is computed by subtracting its value from 2^n , where n is the number
> of bits in the promoted operand. The type of the result is the type of
> the promoted operand." The operand has arithmetic type. Integral
> promotion has no effect. The negative of 1 is computed by subtracting
> its value from 2^32 , resulting in 0xffffffff.

Here you go wrong. The subtraction of 2^32 only happens for _unsigned_
quantities, but 1 is a _signed_ quantity.
Therefor, the result of applying the unary - to 1 results in the value
-1.

>
> Now we look at the left operand of the bitwise inclusive OR and see
> that we need promotion of the right operand.
> (unsigned long)0xffffffff

> The implicit conversion is governed by the rules for integral
> conversion in the Standard (Section 4.7). "If the destination type is
> unsigned, the resulting value is the least unsigned integer congruent
> to the source integer (modulo 2^n where n is the number of bits used
> to represent the unsigned type)." For this conversion, n is 64.
>
> The resulting value is the least unsigned integer congruent to
> 0xffffffff
> modulo
> 0x10000000000000000
> Congruence requires that
> resultingValue % 0x10000000000000000 == 0xffffffff %
> 0x10000000000000000 The least unsigned long for which congruence is
> satisfied is 0x00000000ffffffff

Here you are working too much with bit-patterns.
Most of the C++ standard is written in terms of operations on values,
not the underlying bit-patterns that are used to represent the values.

The conversion of the value -1 to the type unsigned long results in the
value ULONG_MAX, because that is the smallest value for which the
congruence relation
  resultingValue % (ULONG_MAX+1) == -1 % (ULONG_MAX+1)
holds.
Under the LP64 data model, with no padding bits, the value ULONG_MAX
would be represented with the bit-pattern 0xffffffffffffffff.

Note that in the program below, the assert must not trigger under the
LP64/I32 data model (32-bit int, 64-bit long).

#include <cassert>

int main()
{
  unsigned long bundle_loc_mask = ( unsigned long )0 | -1U;
  assert( bundle_loc_mask == 0x00000000ffffffffUL );

  return 0;
}

Bart v Ingen Schenau
--
a.c.l.l.c-c++ FAQ: http://www.comeaucomputing.com/learn/faq
c.l.c FAQ: http://www.eskimo.com/~scs/C-faq/top.html
c.l.c++ FAQ: http://www.parashift.com/c++-faq-lite/

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]