/* This file is extracted from S L Moshier's ioldoubl.c, * modified for use in MinGW * * Extended precision arithmetic functions for long double I/O. * This program has been placed in the public domain. */ /* * Revision history: * * 5 Jan 84 PDP-11 assembly language version * 6 Dec 86 C language version * 30 Aug 88 100 digit version, improved rounding * 15 May 92 80-bit long double support * * Author: S. L. Moshier. * * 6 Oct 02 Modified for MinGW by inlining utility routines, * removing global variables and splitting out strtold * from _IO_ldtoa and _IO_ldtostr. * * Danny Smith * */ #include "cephes_emath.h" /* * The constants are for 64 bit precision. */ /* Move in external format number, * converting it to internal format. */ void __emovi(const short unsigned int * __restrict__ a, short unsigned int * __restrict__ b) { register const unsigned short *p; register unsigned short *q; int i; q = b; p = a + (NE-1); /* point to last word of external number */ /* get the sign bit */ if( *p & 0x8000 ) *q++ = 0xffff; else *q++ = 0; /* get the exponent */ *q = *p--; *q++ &= 0x7fff; /* delete the sign bit */ #ifdef INFINITY if( (*(q-1) & 0x7fff) == 0x7fff ) { #ifdef NANS if( __eisnan(a) ) { *q++ = 0; for( i=3; i> 16) + (m >> 16) + *pp; *pp = (unsigned short )carry; *(pp-1) = carry >> 16; } } for( i=M; i tdenm ) tquot = 0xffff; */ /* Multiply denominator by trial quotient digit. */ __m16m( tquot, den, tprod ); /* The quotient digit may have been overestimated. */ if( __ecmpm( tprod, num ) > 0 ) { tquot -= 1; __esubm( den, tprod ); if( __ecmpm( tprod, num ) > 0 ) { tquot -= 1; __esubm( den, tprod ); } } __esubm( tprod, num ); equot[i] = tquot; __eshup6(num); } /* test for nonzero remainder after roundoff bit */ p = &num[M]; j = 0; for( i=M; i NBITS ) { __ecleazs( s ); return; } #endif exp -= j; #ifndef INFINITY if( exp >= 32767L ) goto overf; #else if( (j > NBITS) && (exp < 32767L) ) { __ecleazs( s ); return; } #endif if( exp < 0L ) { if( exp > (long )(-NBITS-1) ) { j = (int )exp; i = __eshift( s, j ); if( i ) lost = 1; } else { __ecleazs( s ); return; } } /* Round off, unless told not to by rcntrl. */ if( rcntrl == 0 ) goto mdfin; if (rndprc == 64) { rw = 7; re = 6; rbit[NI-2] = 0; rbit[6] = 1; } /* Shift down 1 temporarily if the data structure has an implied * most significant bit and the number is denormal. * For rndprc = 64 or NBITS, there is no implied bit. * But Intel long double denormals lose one bit of significance even so. */ #if IBMPC if( (exp <= 0) && (rndprc != NBITS) ) #else if( (exp <= 0) && (rndprc != 64) && (rndprc != NBITS) ) #endif { lost |= s[NI-1] & 1; __eshdn1(s); } /* Clear out all bits below the rounding bit, * remembering in r if any were nonzero. */ r = s[rw] & rmsk; if( rndprc < NBITS ) { i = rw + 1; while( i < NI ) { if( s[i] ) r |= 1; s[i] = 0; ++i; } } s[rw] &= ~rmsk; if( (r & rmbit) != 0 ) { if( r == rmbit ) { if( lost == 0 ) { /* round to even */ if( (s[re] & 1) == 0 ) goto mddone; } else { if( subflg != 0 ) goto mddone; } } __eaddm( rbit, s ); } mddone: #if IBMPC if( (exp <= 0) && (rndprc != NBITS) ) #else if( (exp <= 0) && (rndprc != 64) && (rndprc != NBITS) ) #endif { __eshup1(s); } if( s[2] != 0 ) { /* overflow on roundoff */ __eshdn1(s); exp += 1; } mdfin: s[NI-1] = 0; if( exp >= 32767L ) { #ifndef INFINITY overf: #endif #ifdef INFINITY s[1] = 32767; for( i=2; i b * 0 if a == b * -1 if a < b * -2 if either a or b is a NaN. */ int __ecmp(const short unsigned int * __restrict__ a, const short unsigned int * __restrict__ b) { unsigned short ai[NI], bi[NI]; register unsigned short *p, *q; register int i; int msign; #ifdef NANS if (__eisnan (a) || __eisnan (b)) return( -2 ); #endif __emovi( a, ai ); p = ai; __emovi( b, bi ); q = bi; if( *p != *q ) { /* the signs are different */ /* -0 equals + 0 */ for( i=1; i 0 ); return(0); /* equality */ diff: if( *(--p) > *(--q) ) return( msign ); /* p is bigger */ else return( -msign ); /* p is littler */ } /* ; Shift significand ; ; Shifts significand area up or down by the number of bits ; given by the variable sc. */ int __eshift(short unsigned int *x, int sc) { unsigned short lost; unsigned short *p; if( sc == 0 ) return( 0 ); lost = 0; p = x + NI-1; if( sc < 0 ) { sc = -sc; while( sc >= 16 ) { lost |= *p; /* remember lost bits */ __eshdn6(x); sc -= 16; } while( sc >= 8 ) { lost |= *p & 0xff; __eshdn8(x); sc -= 8; } while( sc > 0 ) { lost |= *p & 1; __eshdn1(x); sc -= 1; } } else { while( sc >= 16 ) { __eshup6(x); sc -= 16; } while( sc >= 8 ) { __eshup8(x); sc -= 8; } while( sc > 0 ) { __eshup1(x); sc -= 1; } } if( lost ) lost = 1; return( (int )lost ); } /* ; normalize ; ; Shift normalizes the significand area pointed to by argument ; shift count (up = positive) is returned. */ int __enormlz(short unsigned int *x) { register unsigned short *p; int sc; sc = 0; p = &x[M]; if( *p != 0 ) goto normdn; ++p; if( *p & 0x8000 ) return( 0 ); /* already normalized */ while( *p == 0 ) { __eshup6(x); sc += 16; /* With guard word, there are NBITS+16 bits available. * return true if all are zero. */ if( sc > NBITS ) return( sc ); } /* see if high byte is zero */ while( (*p & 0xff00) == 0 ) { __eshup8(x); sc += 8; } /* now shift 1 bit at a time */ while( (*p & 0x8000) == 0) { __eshup1(x); sc += 1; if( sc > (NBITS+16) ) { mtherr( "enormlz", UNDERFLOW ); return( sc ); } } return( sc ); /* Normalize by shifting down out of the high guard word of the significand */ normdn: if( *p & 0xff00 ) { __eshdn8(x); sc -= 8; } while( *p != 0 ) { __eshdn1(x); sc -= 1; if( sc < -NBITS ) { mtherr( "enormlz", OVERFLOW ); return( sc ); } } return( sc ); } /* Move internal format number out, * converting it to external format. */ void __emovo(const short unsigned int * __restrict__ a, short unsigned int * __restrict__ b) { register const unsigned short *p; register unsigned short *q; unsigned short i; p = a; q = b + (NE-1); /* point to output exponent */ /* combine sign and exponent */ i = *p++; if( i ) *q-- = *p++ | 0x8000; else *q-- = *p++; #ifdef INFINITY if( *(p-1) == 0x7fff ) { #ifdef NANS if( __eiisnan(a) ) { __enan_NBITS( b ); return; } #endif __einfin(b); return; } #endif /* skip over guard word */ ++p; /* move the significand */ for( i=0; i= ld ) { if( __ecmpm(den,num) <= 0 ) { __esubm(den, num); j = 1; } else { j = 0; } __eshup1(equot); equot[NI-1] |= j; __eshup1(num); ln -= 1; } __emdnorm( num, 0, 0, ln, 0, NBITS ); } void __eadd1(const short unsigned int * __restrict__ a, const short unsigned int * __restrict__ b, short unsigned int * __restrict__ c, int subflg) { unsigned short ai[NI], bi[NI], ci[NI]; int i, lost, j, k; long lt, lta, ltb; #ifdef INFINITY if( __eisinf(a) ) { __emov(a,c); if( subflg ) __eneg(c); return; } if( __eisinf(b) ) { __emov(b,c); return; } #endif __emovi( a, ai ); __emovi( b, bi ); if( sub ) ai[0] = ~ai[0]; /* compare exponents */ lta = ai[E]; ltb = bi[E]; lt = lta - ltb; if( lt > 0L ) { /* put the larger number in bi */ __emovz( bi, ci ); __emovz( ai, bi ); __emovz( ci, ai ); ltb = bi[E]; lt = -lt; } lost = 0; if( lt != 0L ) { if( lt < (long )(-NBITS-1) ) goto done; /* answer same as larger addend */ k = (int )lt; lost = __eshift( ai, k ); /* shift the smaller number down */ } else { /* exponents were the same, so must compare significands */ i = __ecmpm( ai, bi ); if( i == 0 ) { /* the numbers are identical in magnitude */ /* if different signs, result is zero */ if( ai[0] != bi[0] ) { __eclear(c); return; } /* if same sign, result is double */ /* double denomalized tiny number */ if( (bi[E] == 0) && ((bi[3] & 0x8000) == 0) ) { __eshup1( bi ); goto done; } /* add 1 to exponent unless both are zero! */ for( j=1; j 0 ) { /* put the larger number in bi */ __emovz( bi, ci ); __emovz( ai, bi ); __emovz( ci, ai ); } } if( ai[0] == bi[0] ) { __eaddm( ai, bi ); subflg = 0; } else { __esubm( ai, bi ); subflg = 1; } __emdnorm( bi, lost, subflg, ltb, 64, NBITS); done: __emovo( bi, c ); } /* y = largest integer not greater than x * (truncated toward minus infinity) * * unsigned short x[NE], y[NE] * * efloor( x, y ); */ void __efloor(short unsigned int *x, short unsigned int *y) { register unsigned short *p; int e, expon, i; unsigned short f[NE]; const unsigned short bmask[] = { 0xffff, 0xfffe, 0xfffc, 0xfff8, 0xfff0, 0xffe0, 0xffc0, 0xff80, 0xff00, 0xfe00, 0xfc00, 0xf800, 0xf000, 0xe000, 0xc000, 0x8000, 0x0000, }; __emov( x, f ); /* leave in external format */ expon = (int )f[NE-1]; e = (expon & 0x7fff) - (EXONE - 1); if( e <= 0 ) { __eclear(y); goto isitneg; } /* number of bits to clear out */ e = NBITS - e; __emov( f, y ); if( e <= 0 ) return; p = &y[0]; while( e >= 16 ) { *p++ = 0; e -= 16; } /* clear the remaining bits */ *p &= bmask[e]; /* truncate negatives toward minus infinity */ isitneg: if( (unsigned short )expon & (unsigned short )0x8000 ) { for( i=0; i