Binary numeric promotions question

R

rk

I am surprised about the results (stated in the comments) from the
following operations:

private void button1_Click(object sender, EventArgs e)
{
uint u34 = 0;
double d34 = u34 - 1; // 4294967295.0
double d34a = u34 + (-1); // -1
double d34b = u34 - (+1); // 4294967295.0
}

Since the second operand is of type int, according to the rules given in
the C# specification for "Binary numeric promotions" (section 14.2.6.2)

Binary numeric promotion occurs for the operands of the predefined +,
–, *, /, %, &, |, ^, ==, !=, >, <, >=, and <= binary operators. Binary
numeric promotion implicitly converts both operands to a common type
...

and

• Otherwise, if either operand is of type uint and the other operand
is of type sbyte, short, or int, both operands are converted to type
long.

I would expect both operands to be converted to long, giving the result
-1 in any of the three cases.

Why is the result -1 for d34 and d34b? What I am missing?

Thanks
Richard
 
J

Jeroen Mostert

rk said:
I am surprised about the results (stated in the comments) from the
following operations:

private void button1_Click(object sender, EventArgs e)
{
uint u34 = 0;
double d34 = u34 - 1; // 4294967295.0
double d34a = u34 + (-1); // -1
double d34b = u34 - (+1); // 4294967295.0
}

Since the second operand is of type int, according to the rules given in
the C# specification for "Binary numeric promotions" (section 14.2.6.2)
[...]
I would expect both operands to be converted to long, giving the result
-1 in any of the three cases.
That section is informative, not normative. The reason it's informative is
because the *real* rules are spelled out by the overload resolution
sections, which are quite complicated.

The problem is the use of the constant expressions "1" and "+1". The
compiler is permitted to implicitly convert these to a uint (section
13.1.7), which it is not allowed to do for "-1" (since that cannot be
represented as a uint). Overload resolution on the "-" operator then does
the rest because, by section 14.4.2.3, converting from int to uint (where
possible) is a better conversion than converting from int to long.

Try this instead:

uint u34 = 0;
int x = 1;
double d34 = u34 - x; // -1

Now there is no implicit conversion, and the conversion to long must be used.
 
B

Ben Voigt [C++ MVP]

rk said:
I am surprised about the results (stated in the comments) from the
following operations:

private void button1_Click(object sender, EventArgs e)
{
uint u34 = 0;
double d34 = u34 - 1; // 4294967295.0
double d34a = u34 + (-1); // -1
double d34b = u34 - (+1); // 4294967295.0
}

Since the second operand is of type int, according to the rules given in
the C# specification for "Binary numeric promotions" (section 14.2.6.2)

The second operand isn't of type int, it's a "positive integer literal" (or
negative integer literal in the second case). And the compiler determines
the actual type based on context.

Otherwise you couldn't do:
short s = 2;
You'd need
short s = (short)2;

and that would be highly annoying.
 

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

Top