Skip to content

Negate

Level: 201 · for anyone with a hex editor open

One line: X[i] = -X[i] takes no operand and, on an integer, is two's complement — invert every bit, then add one — so it writes the same bytes signed or unsigned, it undoes itself, and the most negative value of every signed type is its own negative.

What the dialog does

The manual writes Negate as X[i] = -X[i] (Hex Operations) and notes that some operations do not use the operand; this is one of them. On an unsigned type the result is the same wrap as zero minus the value, since an unsigned value has no negative number to become.

In Python

Verified output of negate_py.py — regenerated by tools/run_examples.py, never hand-typed.

1. NEGATE IS INVERT, THEN ADD ONE
------------------------------------------------------------------------
   As Unsigned Byte, and the two steps that make it:

     the bytes        00 01 7f 80 81 ff
     Binary Invert    ff fe 80 7f 7e 00
     ...then Add 1    00 ff 81 80 7f 01
     Negate           00 ff 81 80 7f 01

   The same for all 256 bytes: True

2. SIGNED OR UNSIGNED, THE SAME BYTES
------------------------------------------------------------------------
   Negate 01 writes FF either way. The two settings only disagree
   about what FF is:

     Negate 01 -> ff   as Unsigned Byte 255, as Signed Byte   -1
     Negate 10 -> f0   as Unsigned Byte 240, as Signed Byte  -16
     Negate 80 -> 80   as Unsigned Byte 128, as Signed Byte -128

   All 256 bytes, both settings, the same byte written: True
   An Unsigned Byte has no negative numbers, so -1 wraps to 255 --
   the same wrap as 0 - 1.

3. TWO VALUES ARE THEIR OWN NEGATIVE
------------------------------------------------------------------------
     bytes Negate leaves alone   00 80

   00 is zero. 80 is -128, and +128 does not fit in a Signed Byte, so
   the most negative value is its own negative. Every signed width has
   one:

     Signed Short  00 80        -> 00 80        unchanged: True
     Signed Int    00 00 00 80  -> 00 00 00 80  unchanged: True

4. NEGATE TWICE GIVES THE FILE BACK
------------------------------------------------------------------------
     all 65,536 Signed Shorts   True

5. ON A FLOAT, NEGATE CHANGES ONE BIT
------------------------------------------------------------------------
     1.0  00 00 80 3f -> 00 00 80 bf   reads back -1.0
     0.0  00 00 00 00 -> 00 00 00 80   reads back -0.0

     -0.0 == 0.0 as numbers   True
     ...and as bytes          False

   A float keeps its sign in a bit of its own, the top bit of the last
   byte here, so there is no carry and no wrap -- and zero has two
   spellings that compare equal and are not the same file.

Invert, then add one

Section 1 is the definition of two's complement run on six bytes: Binary Invert flips every bit, Add 1 carries through the result, and what comes out is Negate — for all 256 bytes, not only the six shown. That is why the dialog does not need to know whether a value is signed (section 2): the bits of −x are the same bits whether FF is later read as −1 or as 255.

The value that is its own negative

Section 3 finds two bytes Negate leaves alone. 00 is zero. 80 is −128, the most negative Signed Byte, and its negative, +128, does not fit in a type whose largest value is 127, so it wraps straight back to −128. Every signed width has one such value — 00 80 in a little-endian Short, 00 00 00 80 in a little-endian Int — and it is how an absolute value can come out negative.

A float keeps its sign in a bit

Section 5 negates Floats, and the change is one bit: 1.0 is 00 00 80 3F and −1.0 is 00 00 80 BF, the top bit of the last byte. There is no carry, no wrap and no most-negative value — but zero has two spellings. 0.0 negated is -0.0, the bytes 00 00 00 80, which compare equal to 0.0 as numbers and are not the same four bytes. A check that compares files byte for byte and a check that compares values will disagree about whether anything changed.

What the manual does not say

  • Whether Negate wraps on an Unsigned type as the programs do.
  • Which floating-point types the dialog accepts for Negate.

If you are coming from Python or ABAP

Python. (-b) & 0xFF is Negate as Unsigned Byte, and (~b + 1) & 0xFF is the same byte spelled as its definition. For floats, -x flips the sign bit, math.copysign(0.0, -1.0) asks for −0.0 on purpose, and struct.pack('<f', -0.0) != struct.pack('<f', 0.0) is section 5 in one line.

ABAP. (Not machine-checked — CI cannot run ABAP.) A sign in front of an operand is part of the arithmetic expression ↗, and an integer subtotal outside the type's range raises CX_SY_ARITHMETIC_OVERFLOW. So negating the most negative i is an exception in ABAP, not the fixed point section 3 finds.

Try it

  1. Type 00 01 7F 80 81 FF into a scratch file and Negate as Signed Byte. Before you look, write down which bytes you expect to stay the same.
  2. Negate the same range a second time and confirm the file is back. Then Negate once as Unsigned Byte and read the Inspector's unsigned column.
  3. Put a Float 0.0 into four bytes and Negate it. Compare the bytes, then compare the Inspector's value, and decide which of the two a checksum would see.
  4. Find a four-byte field in a file of your own that could hold the most negative Signed Int, 00 00 00 80 little-endian, write that value into a copy, and Negate it.

See also