Subject: bug in libc quad arithmetic for % operator
To: None <bostic@forge.BSDI.COM, tech-kern@NetBSD.ORG>
From: Chris Torek <torek@BSDI.COM>
List: tech-kern
Date: 10/09/1997 06:27:53
The NetBSD folks found this one; the fix is trivial.  The quad
versions of / and % should produce the same results as the native
arithmetic, but quad `%' is broken.

A little test program shows the problem:

#include <err.h>
#include <stdlib.h>

int
main(argc, argv)
	int argc;
	char **argv;
{
	long la, lb, lq, lr;
	long long lla, llb, llq, llr;

	if (argc < 3)
		errx(1, "usage: mod x y");
	la = strtol(argv[1], 0, 0);
	lb = strtol(argv[2], 0, 0);
	lq = la / lb;
	lr = la % lb;
	printf("long: %ld /%% %ld = %ld, %ld\n", la, lb, lq, lr);

	lla = la;
	llb = lb;
	llq = lla / llb;
	llr = lla % llb;
	printf("ll:   %lld /%% %lld = %lld, %lld\n", lla, llb, llq, llr);
	return 0;
}

Run this with `7 5' and you get the expected (1, 2); with -7 5,
you get (-1, -2); but with 7 -5 you get (-1, 2) vs (-1, -2), and
with -7 -5 you get (1, -2) vs (1, 2).  Clearly divdi3.c is okay
and moddi3.c is broken (although both are technically machine-
dependent).  Here is the one-line fix...

Chris

Index: moddi3.c
===================================================================
RCS file: /master/lib/libc/quad/moddi3.c,v
retrieving revision 2.1
diff -c -2 -r2.1 moddi3.c
*** moddi3.c	1995/02/03 06:35:58	2.1
--- moddi3.c	1997/10/09 12:18:26
***************
*** 45,50 ****
   * Return remainder after dividing two signed quads.
   *
!  * XXX
!  * If -1/2 should produce -1 on this machine, this code is wrong.
   */
  quad_t
--- 45,49 ----
   * Return remainder after dividing two signed quads.
   *
!  * XXX	we assume a % b < 0 iff a < 0, but this is actually machine-dependent.
   */
  quad_t
***************
*** 60,64 ****
  		ua = a, neg = 0;
  	if (b < 0)
! 		ub = -(u_quad_t)b, neg ^= 1;
  	else
  		ub = b;
--- 59,63 ----
  		ua = a, neg = 0;
  	if (b < 0)
! 		ub = -(u_quad_t)b;
  	else
  		ub = b;