/* ceil() * floor() * frexp() * ldexp() * * Single precision floating point numeric utilities * * * * SYNOPSIS: * * float x, y; * float ceil(), floor(), frexp(), ldexp(); * int expnt, n; * * y = floor(x); * y = ceil(x); * y = frexp( x, &expnt ); * y = ldexp( x, n ); * * * * DESCRIPTION: * * All four routines return a single precision floating point * result. * * sfloor() returns the largest integer less than or equal to x. * It truncates toward minus infinity. * * sceil() returns the smallest integer greater than or equal * to x. It truncates toward plus infinity. * * sfrexp() extracts the exponent from x. It returns an integer * power of two to expnt and the significand between 0.5 and 1 * to y. Thus x = y * 2**expn. * * sldexp() multiplies x by 2**n. * * These functions are part of the standard C run time library * for many but not all C compilers. The ones supplied are * written in C for either DEC or IEEE arithmetic. They should * be used only if your compiler library does not already have * them. * * The IEEE versions assume that denormal numbers are implemented * in the arithmetic. Some modifications will be required if * the arithmetic has abrupt rather than gradual underflow. */ /* Cephes Math Library Release 2.1: December, 1988 Copyright 1984, 1987, 1988 by Stephen L. Moshier Direct inquiries to 30 Frost Street, Cambridge, MA 02140 */ #include "mconf.h" #define DENORMAL 1 #ifdef UNK char *unkmsg = "ceil(), floor(), frexp(), ldexp() must be rewritten!\n"; #endif #define EXPMSK 0x807f #define MEXP 255 #define NBITS 24 extern float MAXNUMF; /* (2^24 - 1) * 2^103 */ #ifdef ANSIC float floor(float); #else float floor(); #endif #ifdef ANSIC float ceil( float x ) #else float ceil(x) double x; #endif { float y; #ifdef UNK printf( "%s\n", unkmsg ); return(0.0f); #endif y = floor( (float )x ); if( y < x ) y += 1.0f; return(y); } /* Bit clearing masks: */ static unsigned short bmask[] = { 0xffff, 0xfffe, 0xfffc, 0xfff8, 0xfff0, 0xffe0, 0xffc0, 0xff80, 0xff00, 0xfe00, 0xfc00, 0xf800, 0xf000, 0xe000, 0xc000, 0x8000, 0x0000, }; #ifdef ANSIC float floor( float x ) #else float floor(x) double x; #endif { unsigned short *p; float y; int e; #ifdef UNK printf( "%s\n", unkmsg ); return(0.0f); #endif y = x; /* find the exponent (power of 2) */ #ifdef DEC p = (unsigned short *)&y; e = (( *p >> 7) & 0377) - 0201; p += 3; #endif #ifdef IBMPC p = (unsigned short *)&y + 1; e = (( *p >> 7) & 0xff) - 0x7f; p -= 1; #endif #ifdef MIEEE p = (unsigned short *)&y; e = (( *p >> 7) & 0xff) - 0x7f; p += 1; #endif if( e < 0 ) { if( y < 0 ) return( -1.0f ); else return( 0.0f ); } e = (NBITS -1) - e; /* clean out 16 bits at a time */ while( e >= 16 ) { #ifdef IBMPC *p++ = 0; #endif #ifdef DEC *p-- = 0; #endif #ifdef MIEEE *p-- = 0; #endif e -= 16; } /* clear the remaining bits */ if( e > 0 ) *p &= bmask[e]; if( (x < 0) && (y != x) ) y -= 1.0f; return(y); } #ifdef ANSIC float frexp( float x, int *pw2 ) #else float frexp( x, pw2 ) double x; int *pw2; #endif { float y; int i, k; short *q; y = x; #ifdef UNK printf( "%s\n", unkmsg ); return(0.0f); #endif #ifdef IBMPC q = (short *)&y + 1; #endif #ifdef DEC q = (short *)&y; #endif #ifdef MIEEE q = (short *)&y; #endif /* find the exponent (power of 2) */ i = ( *q >> 7) & 0xff; if( i == 0 ) { if( y == 0.0f ) { *pw2 = 0; return(0.0f); } /* Number is denormal or zero */ #if DENORMAL /* Handle denormal number. */ do { y *= 2.0f; i -= 1; k = ( *q >> 7) & 0xff; } while( k == 0 ); i = i + k; #else *pw2 = 0; return( 0.0f ); #endif /* DENORMAL */ } i -= 0x7e; *pw2 = i; *q &= 0x807f; /* strip all exponent bits */ *q |= 0x3f00; /* mantissa between 0.5 and 1 */ return( y ); } #ifdef ANSIC float ldexp( float x, int pw2 ) #else float ldexp( x, pw2 ) double x; int pw2; #endif { float y; short *q; int e; #ifdef UNK printf( "%s\n", unkmsg ); return(0.0f); #endif y = x; #ifdef DEC q = (short *)&y; #endif #ifdef IBMPC q = (short *)&y + 1; #endif #ifdef MIEEE q = (short *)&y; #endif while( (e = ( *q >> 7) & 0xff) == 0 ) { if( y == 0.0f ) { return( 0.0f ); } /* Input is denormal. */ if( pw2 > 0 ) { y *= 2.0f; pw2 -= 1; } if( pw2 < 0 ) { if( pw2 < -24 ) return( 0.0f ); y *= 0.5f; pw2 += 1; } if( pw2 == 0 ) return(y); } e += pw2; /* Handle overflow */ if( e > MEXP ) { return( MAXNUMF ); } *q &= 0x807f; /* Handle denormalized results */ if( e < 1 ) { #if DENORMAL if( e < -24 ) return( 0.0f ); *q |= 0x80; while( e < 1 ) { y *= 0.5f; e += 1; } e = 0; #else return( 0.0f ); #endif } *q |= (e & 0xff) << 7; return(y); }