1177764Sdas/* @(#)e_fmod.c 1.3 95/01/18 */
2177764Sdas/*-
3177764Sdas * ====================================================
4177764Sdas * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
5177764Sdas *
6177764Sdas * Developed at SunSoft, a Sun Microsystems, Inc. business.
7177764Sdas * Permission to use, copy, modify, and distribute this
8177764Sdas * software is freely granted, provided that this notice
9177764Sdas * is preserved.
10177764Sdas * ====================================================
11177764Sdas */
12177764Sdas
13177764Sdas#include <sys/cdefs.h>
14177764Sdas__FBSDID("$FreeBSD$");
15177764Sdas
16177764Sdas#include <float.h>
17177764Sdas#include <stdint.h>
18177764Sdas
19177764Sdas#include "fpmath.h"
20177764Sdas#include "math.h"
21177764Sdas#include "math_private.h"
22177764Sdas
23177764Sdas#define	BIAS (LDBL_MAX_EXP - 1)
24177764Sdas
25177764Sdas#if LDBL_MANL_SIZE > 32
26177764Sdastypedef	uint64_t manl_t;
27177764Sdas#else
28177764Sdastypedef	uint32_t manl_t;
29177764Sdas#endif
30177764Sdas
31177764Sdas#if LDBL_MANH_SIZE > 32
32177764Sdastypedef	uint64_t manh_t;
33177764Sdas#else
34177764Sdastypedef	uint32_t manh_t;
35177764Sdas#endif
36177764Sdas
37177764Sdas/*
38177764Sdas * These macros add and remove an explicit integer bit in front of the
39177764Sdas * fractional mantissa, if the architecture doesn't have such a bit by
40177764Sdas * default already.
41177764Sdas */
42177764Sdas#ifdef LDBL_IMPLICIT_NBIT
43177764Sdas#define	SET_NBIT(hx)	((hx) | (1ULL << LDBL_MANH_SIZE))
44177764Sdas#define	HFRAC_BITS	LDBL_MANH_SIZE
45177764Sdas#else
46177764Sdas#define	SET_NBIT(hx)	(hx)
47177764Sdas#define	HFRAC_BITS	(LDBL_MANH_SIZE - 1)
48177764Sdas#endif
49177764Sdas
50177764Sdas#define	MANL_SHIFT	(LDBL_MANL_SIZE - 1)
51177764Sdas
52177764Sdasstatic const long double Zero[] = {0.0L, -0.0L};
53177764Sdas
54177764Sdas/*
55177764Sdas * Return the IEEE remainder and set *quo to the last n bits of the
56177764Sdas * quotient, rounded to the nearest integer.  We choose n=31 because
57177764Sdas * we wind up computing all the integer bits of the quotient anyway as
58177764Sdas * a side-effect of computing the remainder by the shift and subtract
59177764Sdas * method.  In practice, this is far more bits than are needed to use
60177764Sdas * remquo in reduction algorithms.
61177764Sdas *
62177764Sdas * Assumptions:
63177764Sdas * - The low part of the mantissa fits in a manl_t exactly.
64177764Sdas * - The high part of the mantissa fits in an int64_t with enough room
65177764Sdas *   for an explicit integer bit in front of the fractional bits.
66177764Sdas */
67177764Sdaslong double
68177764Sdasremquol(long double x, long double y, int *quo)
69177764Sdas{
70177764Sdas	union IEEEl2bits ux, uy;
71177764Sdas	int64_t hx,hz;	/* We need a carry bit even if LDBL_MANH_SIZE is 32. */
72177764Sdas	manh_t hy;
73177764Sdas	manl_t lx,ly,lz;
74177764Sdas	int ix,iy,n,q,sx,sxy;
75177764Sdas
76177764Sdas	ux.e = x;
77177764Sdas	uy.e = y;
78177764Sdas	sx = ux.bits.sign;
79177764Sdas	sxy = sx ^ uy.bits.sign;
80177764Sdas	ux.bits.sign = 0;	/* |x| */
81177764Sdas	uy.bits.sign = 0;	/* |y| */
82177764Sdas	x = ux.e;
83177764Sdas
84177764Sdas    /* purge off exception values */
85177764Sdas	if((uy.bits.exp|uy.bits.manh|uy.bits.manl)==0 || /* y=0 */
86177764Sdas	   (ux.bits.exp == BIAS + LDBL_MAX_EXP) ||	 /* or x not finite */
87177764Sdas	   (uy.bits.exp == BIAS + LDBL_MAX_EXP &&
88177764Sdas	    ((uy.bits.manh&~LDBL_NBIT)|uy.bits.manl)!=0)) /* or y is NaN */
89177764Sdas	    return (x*y)/(x*y);
90177764Sdas	if(ux.bits.exp<=uy.bits.exp) {
91177764Sdas	    if((ux.bits.exp<uy.bits.exp) ||
92177764Sdas	       (ux.bits.manh<=uy.bits.manh &&
93177764Sdas		(ux.bits.manh<uy.bits.manh ||
94177764Sdas		 ux.bits.manl<uy.bits.manl))) {
95177764Sdas		q = 0;
96177764Sdas		goto fixup;	/* |x|<|y| return x or x-y */
97177764Sdas	    }
98177764Sdas	    if(ux.bits.manh==uy.bits.manh && ux.bits.manl==uy.bits.manl) {
99233973Sdas		*quo = (sxy ? -1 : 1);
100177764Sdas		return Zero[sx];	/* |x|=|y| return x*0*/
101177764Sdas	    }
102177764Sdas	}
103177764Sdas
104177764Sdas    /* determine ix = ilogb(x) */
105177764Sdas	if(ux.bits.exp == 0) {	/* subnormal x */
106177764Sdas	    ux.e *= 0x1.0p512;
107177764Sdas	    ix = ux.bits.exp - (BIAS + 512);
108177764Sdas	} else {
109177764Sdas	    ix = ux.bits.exp - BIAS;
110177764Sdas	}
111177764Sdas
112177764Sdas    /* determine iy = ilogb(y) */
113177764Sdas	if(uy.bits.exp == 0) {	/* subnormal y */
114177764Sdas	    uy.e *= 0x1.0p512;
115177764Sdas	    iy = uy.bits.exp - (BIAS + 512);
116177764Sdas	} else {
117177764Sdas	    iy = uy.bits.exp - BIAS;
118177764Sdas	}
119177764Sdas
120177764Sdas    /* set up {hx,lx}, {hy,ly} and align y to x */
121177764Sdas	hx = SET_NBIT(ux.bits.manh);
122177764Sdas	hy = SET_NBIT(uy.bits.manh);
123177764Sdas	lx = ux.bits.manl;
124177764Sdas	ly = uy.bits.manl;
125177764Sdas
126177764Sdas    /* fix point fmod */
127177764Sdas	n = ix - iy;
128177764Sdas	q = 0;
129177764Sdas
130177764Sdas	while(n--) {
131177764Sdas	    hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
132177764Sdas	    if(hz<0){hx = hx+hx+(lx>>MANL_SHIFT); lx = lx+lx;}
133177764Sdas	    else {hx = hz+hz+(lz>>MANL_SHIFT); lx = lz+lz; q++;}
134177764Sdas	    q <<= 1;
135177764Sdas	}
136177764Sdas	hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
137177764Sdas	if(hz>=0) {hx=hz;lx=lz;q++;}
138177764Sdas
139177764Sdas    /* convert back to floating value and restore the sign */
140177764Sdas	if((hx|lx)==0) {			/* return sign(x)*0 */
141233973Sdas	    q &= 0x7fffffff;
142177764Sdas	    *quo = (sxy ? -q : q);
143177764Sdas	    return Zero[sx];
144177764Sdas	}
145181063Sdas	while(hx<(1ULL<<HFRAC_BITS)) {	/* normalize x */
146177764Sdas	    hx = hx+hx+(lx>>MANL_SHIFT); lx = lx+lx;
147177764Sdas	    iy -= 1;
148177764Sdas	}
149177764Sdas	ux.bits.manh = hx; /* The integer bit is truncated here if needed. */
150177764Sdas	ux.bits.manl = lx;
151177764Sdas	if (iy < LDBL_MIN_EXP) {
152177764Sdas	    ux.bits.exp = iy + (BIAS + 512);
153177764Sdas	    ux.e *= 0x1p-512;
154177764Sdas	} else {
155177764Sdas	    ux.bits.exp = iy + BIAS;
156177764Sdas	}
157177764Sdas	ux.bits.sign = 0;
158177764Sdas	x = ux.e;
159177764Sdasfixup:
160177764Sdas	y = fabsl(y);
161177764Sdas	if (y < LDBL_MIN * 2) {
162177764Sdas	    if (x+x>y || (x+x==y && (q & 1))) {
163177764Sdas		q++;
164177764Sdas		x-=y;
165177764Sdas	    }
166177764Sdas	} else if (x>0.5*y || (x==0.5*y && (q & 1))) {
167177764Sdas	    q++;
168177764Sdas	    x-=y;
169177764Sdas	}
170177764Sdas
171177764Sdas	ux.e = x;
172177764Sdas	ux.bits.sign ^= sx;
173177764Sdas	x = ux.e;
174177764Sdas
175177764Sdas	q &= 0x7fffffff;
176177764Sdas	*quo = (sxy ? -q : q);
177177764Sdas	return x;
178177764Sdas}
179