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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* Copyright (c) 1988 AT&T */ 30 /* All Rights Reserved */ 31 32 33 /* 34 * ecvt converts to decimal 35 * the number of digits is specified by ndigit 36 * decpt is set to the position of the decimal point 37 * sign is set to 0 for positive, 1 for negative 38 * 39 */ 40 #pragma weak ecvt = _ecvt 41 #pragma weak fcvt = _fcvt 42 43 #include "synonyms.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