Skip to content

Divide

Level: 201 · for anyone with a hex editor open

One line: X[i] /= Operand is the first operation in the list where the dropdown changes the bytes — F0 divided by 2 is 78 read as 240 and F8 read as −16 — and because the manual writes it in C, it rounds toward zero, which is neither Python's // nor a right shift.

What the dialog does

The manual writes Divide as X[i] /= Operand (Hex Operations). Add, Subtract and Multiply never needed to know what number a value held: they moved bits, and two's complement made the signed and unsigned readings the same bits. Division has to know the number. So Treat Data As, which until now chose only a width, starts choosing a result.

In Python

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

1. ONE DROPDOWN, TWO QUOTIENTS
------------------------------------------------------------------------
   Divide f0 80 ff 7f by 2:

     Unsigned Byte  reads 240, 128, 255, 127   writes 78 40 7f 3f
     Signed Byte    reads -16, -128, -1, 127   writes f8 c0 00 3f

   Byte values that divide differently: 128 of 256,
   and they are exactly 80 to FF: True

   Those are the bytes the two settings read as different numbers. The
   first four operations never had to know the number; Divide does.

2. C ROUNDS TOWARD ZERO, AND PYTHON'S // ROUNDS DOWN
------------------------------------------------------------------------
   The manual writes Divide as C's /=, and C drops the fraction, which
   rounds toward zero. Python's // rounds toward minus infinity. They
   agree until the quotient is negative:

     a / b       C   //   as a Signed Byte, C and //
     7 / 2       3    3   03 and 03
     -7 / 2     -3   -4   fd and fc
     7 / -2     -3   -4   fd and fc
     -1 / 2      0   -1   00 and ff

3. DIVIDE 2 IS NOT SHIFT RIGHT 1
------------------------------------------------------------------------
   Shift Right 1 on a negative Signed Byte copies the sign bit in -- on
   every compiler this library runs -- which rounds toward minus
   infinity, where Divide rounds toward zero:

     values where Divide 2 and Shift Right 1 differ   64 of 256
     every one of them negative and odd               True
     -7, through Divide 2 and Shift Right 1           -3 and -4

4. DIVIDE 0
------------------------------------------------------------------------
   There is no byte to write. This program's answer is Python's:

     Divide 0 on 10   ZeroDivisionError

   C leaves integer division by zero undefined, and the manual does not
   say what the dialog does instead.

5. A FLOAT QUOTIENT IS ROUNDED TO ITS TYPE
------------------------------------------------------------------------
   As Float or Double, Divide is floating-point division. 1 / 3:

     Float   ab aa aa 3e              reads back 0.3333333432674408
     Double  55 55 55 55 55 55 d5 3f  reads back 0.3333333333333333

   Neither is a third. Each is the nearest number its bits can hold,
   and a Float and a Double are nearest in different places.

One dropdown, two quotients

Section 1 divides F0 80 FF 7F by 2 both ways. As Unsigned Byte those are 240, 128, 255 and 127, and the quotients are 78 40 7F 3F. As Signed Byte they are −16, −128, −1 and 127, and the quotients are F8 C0 00 3F. Over all 256 bytes, exactly the 128 from 80 to FF divide differently — the bytes the two settings read as different numbers. 7F is 127 either way and gives the same answer either way.

Which way a quotient rounds

C's integer division drops the fraction, which rounds toward zero: −7 / 2 is −3. Python's // rounds toward minus infinity: −7 // 2 is −4. Section 2 shows them agreeing on every quotient that is not negative and parting on every negative one that is not whole — FD against FC as a Signed Byte. A Python program that reproduces the dialog therefore cannot use //, which is why each program in this chapter that divides defines a four-line c_div().

Section 3 is the same fact meeting Shift Right. On every compiler this library runs, shifting a negative Signed Byte right copies the sign bit in, and that rounds toward minus infinity, like //: −7 >> 1 is −4. So Divide 2 and Shift Right 1 disagree on 64 of the 256 Signed Bytes, every negative odd one, and replacing one with the other is safe only where a value cannot be negative.

Dividing by zero, and by a float

There is no byte to write for Divide 0, and C leaves integer division by zero undefined. Section 4's answer is Python's ZeroDivisionError; what the dialog does is not in the manual, and is worth finding out on a copy of a file. As Float and Double, Divide is floating-point division, and section 5 shows the one thing to expect: 1/3 is a third in neither type, and the two types round it in different places.

What the manual does not say

  • What Divide writes for an operand of 0.
  • What the most negative signed value divided by −1 becomes: the answer, +128 in a Signed Byte, does not fit, and C leaves it undefined.
  • Which types the dialog accepts for Divide.

If you are coming from Python or ABAP

Python. // is floor division, and int(a / b) truncates only while a float can hold the numbers exactly, so neither is C's division in general. On integers of any size, C's quotient is abs(a) // abs(b), negated when the signs differ — c_div() in the program above. divmod() returns the floor pair, which is Modulus's concern.

ABAP. (Not machine-checked — CI cannot run ABAP.) ABAP gives three answers where C gives one, all on one page of the keyword documentation ↗. In an integer calculation / rounds commercially where, as the page says, most languages cut the decimal places off. DIV is the integer part chosen so that MOD is never negative, which for a negative dividend and a positive divisor rounds down, like Python's //. And division by zero raises an exception, except 0 divided by 0, which the same page says gives 0.

Try it

  1. Type F0 80 FF 7F into a scratch file and Divide 2 as Unsigned Byte; undo, and Divide 2 as Signed Byte. Predict each byte from section 1 before you look.
  2. On a copy of a file, Divide a few bytes by 0 and note what the dialog says or writes. Then try the most negative Signed Short, 00 80 little-endian, divided by −1.
  3. Divide 1.0 by 3 as Float in one copy and as Double in another, and compare what the Inspector shows for each.
  4. Take a run of negative Signed Bytes, Divide 2 in one copy and Shift Right 1 in another, and compare the two files with Tools > Compare. Every byte that differs should have started as a negative odd number.

See also