g_ddfmt.c revision 225736
11573Srgrimes/****************************************************************
21573Srgrimes
31573SrgrimesThe author of this software is David M. Gay.
41573Srgrimes
51573SrgrimesCopyright (C) 1998 by Lucent Technologies
61573SrgrimesAll Rights Reserved
71573Srgrimes
81573SrgrimesPermission to use, copy, modify, and distribute this software and
91573Srgrimesits documentation for any purpose and without fee is hereby
101573Srgrimesgranted, provided that the above copyright notice appear in all
111573Srgrimescopies and that both that the copyright notice and this
121573Srgrimespermission notice and warranty disclaimer appear in supporting
131573Srgrimesdocumentation, and that the name of Lucent or any of its entities
141573Srgrimesnot be used in advertising or publicity pertaining to
151573Srgrimesdistribution of the software without specific, written prior
161573Srgrimespermission.
171573Srgrimes
181573SrgrimesLUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
191573SrgrimesINCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
201573SrgrimesIN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
211573SrgrimesSPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
221573SrgrimesWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
231573SrgrimesIN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
241573SrgrimesARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
251573SrgrimesTHIS SOFTWARE.
261573Srgrimes
271573Srgrimes****************************************************************/
281573Srgrimes
291573Srgrimes/* Please send bug reports to David M. Gay (dmg@acm.org). */
301573Srgrimes
311573Srgrimes#include "gdtoaimp.h"
3282995Sache#include <string.h>
3382995Sache
341573Srgrimes char *
351573Srgrimes#ifdef KR_headers
361573Srgrimesg_ddfmt(buf, dd0, ndig, bufsize) char *buf; double *dd0; int ndig; size_t bufsize;
371573Srgrimes#else
381573Srgrimesg_ddfmt(char *buf, double *dd0, int ndig, size_t bufsize)
391573Srgrimes#endif
401573Srgrimes{
411573Srgrimes	FPI fpi;
421573Srgrimes	char *b, *s, *se;
431573Srgrimes	ULong *L, bits0[4], *bits, *zx;
441573Srgrimes	int bx, by, decpt, ex, ey, i, j, mode;
451573Srgrimes	Bigint *x, *y, *z;
461573Srgrimes	U *dd, ddx[2];
471573Srgrimes#ifdef Honor_FLT_ROUNDS /*{{*/
481573Srgrimes	int Rounding;
4982975Sache#ifdef Trust_FLT_ROUNDS /*{{ only define this if FLT_ROUNDS really works! */
501573Srgrimes	Rounding = Flt_Rounds;
511573Srgrimes#else /*}{*/
521573Srgrimes	Rounding = 1;
531573Srgrimes	switch(fegetround()) {
541573Srgrimes	  case FE_TOWARDZERO:	Rounding = 0; break;
551573Srgrimes	  case FE_UPWARD:	Rounding = 2; break;
5687016Sache	  case FE_DOWNWARD:	Rounding = 3;
571573Srgrimes	  }
5887016Sache#endif /*}}*/
5987016Sache#else /*}{*/
6087016Sache#define Rounding FPI_Round_near
6187016Sache#endif /*}}*/
6287016Sache
631573Srgrimes	if (bufsize < 10 || bufsize < ndig + 8)
641573Srgrimes		return 0;
651573Srgrimes
661573Srgrimes	dd = (U*)dd0;
671573Srgrimes	L = dd->L;
681573Srgrimes	if ((L[_0] & 0x7ff00000L) == 0x7ff00000L) {
6982975Sache		/* Infinity or NaN */
701573Srgrimes		if (L[_0] & 0xfffff || L[_1]) {
711573Srgrimes nanret:
721573Srgrimes			return strcp(buf, "NaN");
731573Srgrimes			}
741573Srgrimes		if ((L[2+_0] & 0x7ff00000) == 0x7ff00000) {
751573Srgrimes			if (L[2+_0] & 0xfffff || L[2+_1])
7682975Sache				goto nanret;
7782975Sache			if ((L[_0] ^ L[2+_0]) & 0x80000000L)
7882975Sache				goto nanret;	/* Infinity - Infinity */
7982975Sache			}
8082975Sache infret:
811573Srgrimes		b = buf;
821573Srgrimes		if (L[_0] & 0x80000000L)
831573Srgrimes			*b++ = '-';
841573Srgrimes		return strcp(b, "Infinity");
851573Srgrimes		}
861573Srgrimes	if ((L[2+_0] & 0x7ff00000) == 0x7ff00000) {
871573Srgrimes		L += 2;
881573Srgrimes		if (L[_0] & 0xfffff || L[_1])
8982982Sache			goto nanret;
9087016Sache		goto infret;
9182975Sache		}
921573Srgrimes	if (dval(&dd[0]) + dval(&dd[1]) == 0.) {
931573Srgrimes		b = buf;
941573Srgrimes#ifndef IGNORE_ZERO_SIGN
951573Srgrimes		if (L[_0] & L[2+_0] & 0x80000000L)
961573Srgrimes			*b++ = '-';
971573Srgrimes#endif
981573Srgrimes		*b++ = '0';
991573Srgrimes		*b = 0;
1001573Srgrimes		return b;
1011573Srgrimes		}
1021573Srgrimes	if ((L[_0] & 0x7ff00000L) < (L[2+_0] & 0x7ff00000L)) {
1031573Srgrimes		dval(&ddx[1]) = dval(&dd[0]);
1041573Srgrimes		dval(&ddx[0]) = dval(&dd[1]);
1051573Srgrimes		dd = ddx;
1061573Srgrimes		L = dd->L;
10782975Sache		}
1081573Srgrimes	z = d2b(dval(&dd[0]), &ex, &bx);
1091573Srgrimes	if (dval(&dd[1]) == 0.)
11087016Sache		goto no_y;
11182975Sache	x = z;
11282975Sache	y = d2b(dval(&dd[1]), &ey, &by);
11382975Sache	if ( (i = ex - ey) !=0) {
11482982Sache		if (i > 0) {
11587016Sache			x = lshift(x, i);
11687016Sache			ex = ey;
11787016Sache			}
1181573Srgrimes		else
1191573Srgrimes			y = lshift(y, -i);
1201573Srgrimes		}
1211573Srgrimes	if ((L[_0] ^ L[2+_0]) & 0x80000000L) {
1221573Srgrimes		z = diff(x, y);
12317141Sjkh		if (L[_0] & 0x80000000L)
1241573Srgrimes			z->sign = 1 - z->sign;
1251573Srgrimes		}
1261573Srgrimes	else {
1271573Srgrimes		z = sum(x, y);
1281573Srgrimes		if (L[_0] & 0x80000000L)
1291573Srgrimes			z->sign = 1;
1301573Srgrimes		}
1311573Srgrimes	Bfree(x);
1321573Srgrimes	Bfree(y);
1331573Srgrimes no_y:
13482975Sache	bits = zx = z->x;
13582975Sache	for(i = 0; !*zx; zx++)
13682975Sache		i += 32;
1371573Srgrimes	i += lo0bits(zx);
1381573Srgrimes	if (i) {
13982975Sache		rshift(z, i);
1401573Srgrimes		ex += i;
1411573Srgrimes		}
1421573Srgrimes	fpi.nbits = z->wds * 32 - hi0bits(z->x[j = z->wds-1]);
143	if (fpi.nbits < 106) {
144		fpi.nbits = 106;
145		if (j < 3) {
146			for(i = 0; i <= j; i++)
147				bits0[i] = bits[i];
148			while(i < 4)
149				bits0[i++] = 0;
150			bits = bits0;
151			}
152		}
153	mode = 2;
154	if (ndig <= 0) {
155		if (bufsize < (int)(fpi.nbits * .301029995664) + 10) {
156			Bfree(z);
157			return 0;
158			}
159		mode = 0;
160		}
161	fpi.emin = 1-1023-53+1;
162	fpi.emax = 2046-1023-106+1;
163	fpi.rounding = Rounding;
164	fpi.sudden_underflow = 0;
165	i = STRTOG_Normal;
166	s = gdtoa(&fpi, ex, bits, &i, mode, ndig, &decpt, &se);
167	b = g__fmt(buf, s, se, decpt, z->sign, bufsize);
168	Bfree(z);
169	return b;
170	}
171