11dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* @(#)e_fmod.c 1.3 95/01/18 */ 21dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/*- 31dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * ==================================================== 41dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. 51dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 61dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Developed at SunSoft, a Sun Microsystems, Inc. business. 71dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Permission to use, copy, modify, and distribute this 81dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * software is freely granted, provided that this notice 91dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * is preserved. 101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * ==================================================== 111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */ 121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <sys/cdefs.h> 14a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes__FBSDID("$FreeBSD$"); 151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include "math.h" 171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include "math_private.h" 181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectstatic const float Zero[] = {0.0, -0.0,}; 201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/* 221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Return the IEEE remainder and set *quo to the last n bits of the 231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * quotient, rounded to the nearest integer. We choose n=31 because 241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * we wind up computing all the integer bits of the quotient anyway as 251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * a side-effect of computing the remainder by the shift and subtract 261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * method. In practice, this is far more bits than are needed to use 271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * remquo in reduction algorithms. 281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */ 291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectfloat 301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectremquof(float x, float y, int *quo) 311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{ 321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project int32_t n,hx,hy,hz,ix,iy,sx,i; 331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project u_int32_t q,sxy; 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 sxy = (hx ^ hy) & 0x80000000; 381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project sx = hx&0x80000000; /* sign of x */ 391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project hx ^=sx; /* |x| */ 401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project hy &= 0x7fffffff; /* |y| */ 411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 421dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project /* purge off exception values */ 431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if(hy==0||hx>=0x7f800000||hy>0x7f800000) /* y=0,NaN;or x not finite */ 441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return (x*y)/(x*y); 451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if(hx<hy) { 461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project q = 0; 471dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project goto fixup; /* |x|<|y| return x or x-y */ 481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } else if(hx==hy) { 49a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes *quo = (sxy ? -1 : 1); 501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return Zero[(u_int32_t)sx>>31]; /* |x|=|y| return x*0*/ 511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project /* determine ix = ilogb(x) */ 541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if(hx<0x00800000) { /* subnormal x */ 551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project for (ix = -126,i=(hx<<8); i>0; i<<=1) ix -=1; 561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } else ix = (hx>>23)-127; 571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 581dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project /* determine iy = ilogb(y) */ 591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if(hy<0x00800000) { /* subnormal y */ 601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project for (iy = -126,i=(hy<<8); i>0; i<<=1) iy -=1; 611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } else iy = (hy>>23)-127; 621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project /* set up {hx,lx}, {hy,ly} and align y to x */ 641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if(ix >= -126) 651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project hx = 0x00800000|(0x007fffff&hx); 661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project else { /* subnormal x, shift x to normal */ 671dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project n = -126-ix; 681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project hx <<= n; 691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if(iy >= -126) 711dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project hy = 0x00800000|(0x007fffff&hy); 721dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project else { /* subnormal y, shift y to normal */ 731dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project n = -126-iy; 741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project hy <<= n; 751dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 761dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project /* fix point fmod */ 781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project n = ix - iy; 791dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project q = 0; 801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project while(n--) { 811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project hz=hx-hy; 821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if(hz<0) hx = hx << 1; 831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project else {hx = hz << 1; q++;} 841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project q <<= 1; 851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project hz=hx-hy; 871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if(hz>=0) {hx=hz;q++;} 881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project 891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project /* convert back to floating value and restore the sign */ 901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if(hx==0) { /* return sign(x)*0 */ 91a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes q &= 0x7fffffff; 92a0ee07829a9ba7e99ef68e8c12551301cc797f0fElliott Hughes *quo = (sxy ? -q : q); 931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return Zero[(u_int32_t)sx>>31]; 941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project while(hx<0x00800000) { /* normalize x */ 961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project hx <<= 1; 971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project iy -= 1; 981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if(iy>= -126) { /* normalize output */ 1001dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project hx = ((hx-0x00800000)|((iy+127)<<23)); 1011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } else { /* subnormal output */ 1021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project n = -126 - iy; 1031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project hx >>= n; 1041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 1051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectfixup: 1061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project SET_FLOAT_WORD(x,hx); 1071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project y = fabsf(y); 1081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (y < 0x1p-125f) { 1091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project if (x+x>y || (x+x==y && (q & 1))) { 1101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project q++; 1111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project x-=y; 1121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 1131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } else if (x>0.5f*y || (x==0.5f*y && (q & 1))) { 1141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project q++; 1151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project x-=y; 1161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project } 1171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project GET_FLOAT_WORD(hx,x); 1181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project SET_FLOAT_WORD(x,hx^sx); 1191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project q &= 0x7fffffff; 1201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *quo = (sxy ? -q : q); 1211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project return x; 1221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project} 123