11dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* e_fmodf.c -- float version of e_fmod.c.
21dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
31dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
41dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
51dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/*
61dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * ====================================================
71dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
81dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
91dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Developed at SunPro, a Sun Microsystems, Inc. business.
101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Permission to use, copy, modify, and distribute this
111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * software is freely granted, provided that this notice
121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * is preserved.
131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * ====================================================
141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
16a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes#include <sys/cdefs.h>
17a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes__FBSDID("$FreeBSD$");
181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/*
201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * __ieee754_fmodf(x,y)
211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Return x mod y in exact arithmetic
221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Method: shift and subtract
231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include "math.h"
261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include "math_private.h"
271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic const float one = 1.0, Zero[] = {0.0, -0.0,};
291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectfloat
311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project__ieee754_fmodf(float x, float y)
321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	int32_t n,hx,hy,hz,ix,iy,sx,i;
341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	GET_FLOAT_WORD(hx,x);
361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	GET_FLOAT_WORD(hy,y);
371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	sx = hx&0x80000000;		/* sign of x */
381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	hx ^=sx;		/* |x| */
391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	hy &= 0x7fffffff;	/* |y| */
401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* purge off exception values */
421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	if(hy==0||(hx>=0x7f800000)||		/* y=0,or x not finite */
431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	   (hy>0x7f800000))			/* or y is NaN */
441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	    return (x*y)/(x*y);
451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	if(hx<hy) return x;			/* |x|<|y| return x */
461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	if(hx==hy)
471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	    return Zero[(u_int32_t)sx>>31];	/* |x|=|y| return x*0*/
481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* determine ix = ilogb(x) */
501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	if(hx<0x00800000) {	/* subnormal x */
511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	    for (ix = -126,i=(hx<<8); i>0; i<<=1) ix -=1;
521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	} else ix = (hx>>23)-127;
531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* determine iy = ilogb(y) */
551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	if(hy<0x00800000) {	/* subnormal y */
561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	    for (iy = -126,i=(hy<<8); i>=0; i<<=1) iy -=1;
571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	} else iy = (hy>>23)-127;
581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* set up {hx,lx}, {hy,ly} and align y to x */
601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	if(ix >= -126)
611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	    hx = 0x00800000|(0x007fffff&hx);
621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	else {		/* subnormal x, shift x to normal */
631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	    n = -126-ix;
641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	    hx = hx<<n;
651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	}
661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	if(iy >= -126)
671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	    hy = 0x00800000|(0x007fffff&hy);
681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	else {		/* subnormal y, shift y to normal */
691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	    n = -126-iy;
701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	    hy = hy<<n;
711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	}
721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* fix point fmod */
741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	n = ix - iy;
751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	while(n--) {
761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	    hz=hx-hy;
771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	    if(hz<0){hx = hx+hx;}
781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	    else {
791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	    	if(hz==0) 		/* return sign(x)*0 */
801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		    return Zero[(u_int32_t)sx>>31];
811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	    	hx = hz+hz;
821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	    }
831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	}
841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	hz=hx-hy;
851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	if(hz>=0) {hx=hz;}
861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project    /* convert back to floating value and restore the sign */
881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	if(hx==0) 			/* return sign(x)*0 */
891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	    return Zero[(u_int32_t)sx>>31];
901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	while(hx<0x00800000) {		/* normalize x */
911dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	    hx = hx+hx;
921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	    iy -= 1;
931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	}
941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	if(iy>= -126) {		/* normalize output */
951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	    hx = ((hx-0x00800000)|((iy+127)<<23));
961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	    SET_FLOAT_WORD(x,hx|sx);
971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	} else {		/* subnormal output */
981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	    n = -126 - iy;
991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	    hx >>= n;
1001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	    SET_FLOAT_WORD(x,hx|sx);
1011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	    x *= one;		/* create necessary signal */
1021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	}
1031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	return x;		/* exact output */
1041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
105