Home | History | Annotate | Download | only in gen
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 
     22 /*
     23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 
     27 /*	Copyright (c) 1988 AT&T	*/
     28 /*	  All Rights Reserved  	*/
     29 
     30 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     31 
     32 /*
     33  *	ecvt converts to decimal
     34  *	the number of digits is specified by ndigit
     35  *	decpt is set to the position of the decimal point
     36  *	sign is set to 0 for positive, 1 for negative
     37  *
     38  */
     39 
     40 #pragma weak _ecvt = ecvt
     41 #pragma weak _fcvt = fcvt
     42 
     43 #include "lint.h"
     44 #include <sys/types.h>
     45 #include <values.h>
     46 #include <nan.h>
     47 #include <string.h>
     48 #include "tsd.h"
     49 
     50 #define	NMAX	((DSIGNIF * 3 + 19)/10) /* restrict max precision */
     51 #define	NDIG	80
     52 
     53 static char *cvt(double, int, int *, int *, int);
     54 
     55 char *
     56 ecvt(double value, int ndigit, int *decpt, int *sign)
     57 {
     58 	return (cvt(value, ndigit, decpt, sign, 0));
     59 }
     60 
     61 char *
     62 fcvt(double value, int ndigit, int *decpt, int *sign)
     63 {
     64 	return (cvt(value, ndigit, decpt, sign, 1));
     65 }
     66 
     67 static char *
     68 cvt(double value, int ndigit, int *decpt, int *sign, int f_flag)
     69 {
     70 	char *buf = tsdalloc(_T_ECVT, NDIG, NULL);
     71 	char *p = &buf[0], *p_last = &buf[ndigit];
     72 
     73 	buf[0] = '\0';
     74 
     75 	if (IsNANorINF(value)) {
     76 		if (IsINF(value))  /* value is an INF, return "inf" */
     77 			(void) strncpy(buf, "inf", NDIG);
     78 		else /* value is a NaN, return "NaN" */
     79 			(void) strncpy(buf, "nan", NDIG);
     80 
     81 		return (buf);
     82 	}
     83 
     84 	if ((*sign = (value < 0.0)) != 0)
     85 		value = -value;
     86 	*decpt = 0;
     87 	if (value != 0.0) {
     88 /*
     89  * rescale to range [1.0, 10.0)
     90  * in binary for speed and to minimize error build-up
     91  * even for the IEEE standard with its high exponents,
     92  *  it's probably better for speed to just loop on them
     93  */
     94 		static const struct s { double p10; int n; } s[] = {
     95 			1e32,	32,
     96 			1e16,	16,
     97 			1e8,	8,
     98 			1e4,	4,
     99 			1e2,	2,
    100 			1e1,	1,
    101 		};
    102 		const struct s *sp = s;
    103 
    104 		++*decpt;
    105 		if (value >= 2.0 * MAXPOWTWO) /* can't be precisely integral */
    106 			do {
    107 				for (; value >= sp->p10; *decpt += sp->n)
    108 					value /= sp->p10;
    109 			} while (sp++->n > 1);
    110 		else if (value >= 10.0) { /* convert integer part separately */
    111 			double pow10 = 10.0, powtemp;
    112 
    113 			while ((powtemp = 10.0 * pow10) <= value)
    114 				pow10 = powtemp;
    115 			for (; ; pow10 /= 10.0) {
    116 				int digit = value/pow10;
    117 				*p++ = digit + '0';
    118 				value -= digit * pow10;
    119 				++*decpt;
    120 				if (pow10 <= 10.0)
    121 					break;
    122 			}
    123 		} else if (value < 1.0)
    124 			do {
    125 				for (; value * sp->p10 < 10.0; *decpt -= sp->n)
    126 					value *= sp->p10;
    127 			} while (sp++->n > 1);
    128 	}
    129 	if (f_flag)
    130 		p_last += *decpt;
    131 	if (p_last >= buf) {
    132 		if (p_last > &buf[NDIG - 2])
    133 			p_last = &buf[NDIG - 2];
    134 		for (; ; ++p) {
    135 			if (value == 0 || p >= &buf[NMAX])
    136 				*p = '0';
    137 			else {
    138 				int intx; /* intx in [0, 9] */
    139 				*p = (intx = (int)value) + '0';
    140 				value = 10.0 * (value - (double)intx);
    141 			}
    142 			if (p >= p_last) {
    143 				p = p_last;
    144 				break;
    145 			}
    146 		}
    147 		if (*p >= '5') /* check rounding in last place + 1 */
    148 			do {
    149 				if (p == buf) { /* rollover from 99999... */
    150 					buf[0] = '1'; /* later digits are 0 */
    151 					++*decpt;
    152 					if (f_flag)
    153 						++p_last;
    154 					break;
    155 				}
    156 				*p = '0';
    157 			} while (++*--p > '9'); /* propagate carries left */
    158 		*p_last = '\0';
    159 	}
    160 	return (buf);
    161 }
    162