Assuming two's complement representation of signed integers and arithmetic shift behaviour of >> operator, the answer could be:
int dl18(int x, int n) {
if (x < 0) {
x += (1 << n) - 1;
}
return x >> n;
}
The addition is necessary, because >> rounds for negative numbers towards negative infinity. By adding 2^n - 1, the result is always truncated towards zero, just like it happens for / operator.
Due to your requirements, assuming that int has 4 bytes (and to be extra pedantic CHAR_BIT = 8), the expression may be rewritten (obfuscated) as:
(x + ((x >> 31) & ((1 << n) + ~0))) >> n
The idea of x >> 31 is to replicate MSB bit, so the mask becomes either all ones (i.e. 0xFFFFFFFF), or all zeros, which is then used to either preserve or eliminate ((1 << n) - 1) from addition. Parentheses around & are necessary, because addition has higher precedence than bitwise AND.
This algorithm is also used by GCC compiler. For instance:
int dl18_4(int x) { return x / 4; }
translates with -O1 into:
dl18_4:
lea eax, [rdi+3] ; eax = rdi + 3
test edi, edi ; set sign flag if edi < 0
cmovns eax, edi ; eax = edi if SF = 0
sar eax, 2 ; eax = eax >> 2
ret
Note that shifting by negative number invokes undefined behavior, so it may be safer to declare second parameter as unsigned int.
/is binary too. "Binary" means it has two operands as opposed to "unary" and "ternary".>>has~and others), shift, and negate again - which certainly should work except for maybe corner cases. Then I would post looking for simplifications.