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¶
- Type
00 01 7F 80 81 FFinto a scratch file and Negate as Signed Byte. Before you look, write down which bytes you expect to stay the same. - 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.
- 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.
- Find a four-byte field in a file of your own that could hold the most negative Signed Int,
00 00 00 80little-endian, write that value into a copy, and Negate it.
See also¶
- Binary Invert — the first half of Negate
- Subtract — zero minus one, from the other side
- Divide — the other operation the most negative value breaks
- Arithmetic has its own width — why +128 has nowhere to go