My question is, does anyone know of a good way of achieving this on the G0 which does not actually have a division instruction.
I do not know of any general purpose approach faster than what the compiler would already do.
There are ways to be faster than general purpose code if:
The range of the numerator (dividend) is non-negative.
The range of the denominator (divisor) is positive.
We can ignore INT_MIN/-1
Rounding mode ties are away from 0 (shown below) rather than ties to even.
Let q = rounded_division(a, b)
Use div()
which computes a/b
and a%b
in a single operation.
#include <stdlib.h>
div_t qr = div(a, b);
if (qr.quot >= 0) {
if (a >= 0) {
if (b/2 > r.rem) qr.quot++;
} else {
if (b/2 < r.rem) qr.quot--;
}
} else {
if (a >= 0) {
if (b/2 < r.rem) qr.quot--;
} else {
if (b/2 > r.rem) qr.quot++;
}
}
- When
a >= 0
and b > 0
and a + b/2
does not overflow:
Add half the divisor before dividing.
q = (a + b/2)/b;
- When
a + b/2
(a - b/2
) does not overflow:
Add half (with select sign) to the divisor before dividing.
// If a and b have the same sign ...
if ((a < 0) == (b < 0)) {
q = (a + b/2)/b;
} else {
q = (a - b/2)/b;
}
The rounding done here is "round to nearest, ties away from 0".
Some potential optimizations possible with sign compares yet often harder to understand. Often the compile will emit good code without such crafted code. Example:
// if ((a < 0) == (b < 0)) {
if (!((a ^ b) & INT_MIN)) {
Division by 0 and INT_MIN/-1
remain undefined behavior (UB).
(I hope I coded all the cases right. Somewhat late. so will review again later.)