15

Consider this unit test code:

    [TestMethod]
    public void RunNotTest()
    {

        // 10101100 = 128 + 32 + 8 + 4 = 172
        byte b = 172;

        // 01010011 = 64 + 16 + 2 + 1 = 83
        Assert.AreEqual(83, (byte)~b);
    }

This test passes. However without the byte cast it fails because the "~" operator returns a value of -173. Why is this?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
S. Valmont
  • 941
  • 2
  • 11
  • 25

2 Answers2

18

A promotion to int occurs on byte because binary complement is not defined for them.

See Unary numeric promotions and Bitwise complement operator.

Intrinsically, when you call ~ on the unsigned 8 bit value 10101100, it is promoted to the 32-bit signed value 0...010101100. Its complement is the 32-bit value 1...101010011, which is equal to -173 for int. A cast of this result into byte is a demotion to the unsigned 8-bit value 01010011, losing the most significant 24 bits. The end result is interpreted as 83 in an unsigned representation.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Tugrul Ates
  • 9,451
  • 2
  • 33
  • 59
  • 10
    Man the `byte` data type is a royal pain. – BoltClock Jul 25 '11 at 02:25
  • @BoltClock: In C, on a 32-bit machine, an unsigned integer generally represents a member of the abstract algebraic ring Z[4294967296], and smaller unsigned types generally behave as members of the rings Z[256] and Z[65536]; signed values, however, are taken to represent numerical quantities. The .NET framework assumes all integer types represent numerical quantities without their representable range, and languages mostly do likewise except that C# can perform certain operations involving signed or unsigned 32- or 64-bit integers as though they represent members of algebraic rings. – supercat Sep 30 '13 at 18:29
  • 1
    @BoltClock: In C, smaller unsigned types get promoted to larger ones, but converting back to the smaller types will yield results which are usually the same as they would have been using the smaller algebraic rings. In C#, however, certain typecasts may fail if code is running in a checked arithmetic context. What's really needed is a type that behaves like a Z[256] or Z[65536] and can inter-operate nicely with `int`. – supercat Sep 30 '13 at 18:37
4

Because ~ returns an int. See ~ Operator (C# Reference) (MSDN)

It is only predefined for int, uint, long, and ulong - so there is an implicit cast when using it on byte.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Yahia
  • 69,653
  • 9
  • 115
  • 144