Code: Select all
#define USE_STDOUT
#include <stdlib.h>
#include <stdio.h>
int a = -123;
int c = 2;
main(void) {
int b = -123;
printf("a=%d, a/2=%d, divide16signed(a,2)=%d, a%%2=%d, (a/2)*2+a%%2=%d\n", a, a/2, a/c, a%c, (a/c)*c+a%c);
printf("b=%d, b/2=%d, divide16signed(b,2)=%d, b%%2=%d, (b/2)*2+b%%2=%d\n", b, b/2, b/c, b%2, (b/2)*c+b%c);
return 0;
}
Code: Select all
a=-123, a/2=-62, divide16signed(a,2)=-62, a%2=1, (a/2)*2+a%2=-123
b=-123, b/2=-61, divide16signed(b,2)=-62, b%2=-1, (b/2)*2+b%2=-121
Code: Select all
a=-123, a/2=-61, divide16signed(a,2)=-61, a%2=-1, (a/2)*2+a%2=-123
b=-123, b/2=-61, divide16signed(b,2)=-61, b%2=-1, (b/2)*2+b%2=-123
However, in gcc (and most C compilers), division of signed binary numbers round towards 0 (which, if the result is negative, means it rounds up). And it is actually a C standard:
Code: Select all
6.5.5 Multiplicative operators
6 When integers are divided, the result of the / operator is the algebraic quotient with any fractional part discarded (Note 88). If the quotient a/b is representable, the expression (a/b)*b + a%b shall equal a.
(88) This is often called "truncation toward zero".
If we want to follow the ANSI-C, the compiler is still possible to optimize division as right shift, by just doing the following:
Code: Select all
/* We want to do A0/2 */
ldc C0, -15
ashl A0, C0, A1 // if A0 is a negative number, A1 = -1; 0 elsewise
asr A0,A0 // right shift A0 as usual
sub A0,A1,A0 // add the result by 1 if A0 is negative
Workaround:
Replace code a/(2^n) with:
Code: Select all
(a>>n)-(a>>15)
Code: Select all
(a>>n)-(a>>31)