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 /* 31 * ecvt converts to decimal 32 * the number of digits is specified by ndigit 33 * decpt is set to the position of the decimal point 34 * sign is set to 0 for positive, 1 for negative 35 * 36 */ 37 38 #pragma weak _ecvt = ecvt 39 #pragma weak _fcvt = fcvt 40 41 #include "lint.h" 42 #include <sys/types.h> 43 #include <values.h> 44 #include <nan.h> 45 #include <string.h> 46 #include "tsd.h" 47 48 #define NMAX ((DSIGNIF * 3 + 19)/10) /* restrict max precision */ 49 #define NDIG 80 50 51 static char *cvt(double, int, int *, int *, int); 52 53 char * 54 ecvt(double value, int ndigit, int *decpt, int *sign) 55 { 56 return (cvt(value, ndigit, decpt, sign, 0)); 57 } 58 59 char * 60 fcvt(double value, int ndigit, int *decpt, int *sign) 61 { 62 return (cvt(value, ndigit, decpt, sign, 1)); 63 } 64 65 static char * 66 cvt(double value, int ndigit, int *decpt, int *sign, int f_flag) 67 { 68 char *buf = tsdalloc(_T_ECVT, NDIG, NULL); 69 char *p = &buf[0], *p_last = &buf[ndigit]; 70 71 buf[0] = '\0'; 72 73 if (IsNANorINF(value)) { 74 if (IsINF(value)) /* value is an INF, return "inf" */ 75 (void) strncpy(buf, "inf", NDIG); 76 else /* value is a NaN, return "NaN" */ 77 (void) strncpy(buf, "nan", NDIG); 78 79 return (buf); 80 } 81 82 if ((*sign = (value < 0.0)) != 0) 83 value = -value; 84 *decpt = 0; 85 if (value != 0.0) { 86 /* 87 * rescale to range [1.0, 10.0) 88 * in binary for speed and to minimize error build-up 89 * even for the IEEE standard with its high exponents, 90 * it's probably better for speed to just loop on them 91 */ 92 static const struct s { double p10; int n; } s[] = { 93 1e32, 32, 94 1e16, 16, 95 1e8, 8, 96 1e4, 4, 97 1e2, 2, 98 1e1, 1, 99 }; 100 const struct s *sp = s; 101 102 ++*decpt; 103 if (value >= 2.0 * MAXPOWTWO) /* can't be precisely integral */ 104 do { 105 for (; value >= sp->p10; *decpt += sp->n) 106 value /= sp->p10; 107 } while (sp++->n > 1); 108 else if (value >= 10.0) { /* convert integer part separately */ 109 double pow10 = 10.0, powtemp; 110 111 while ((powtemp = 10.0 * pow10) <= value) 112 pow10 = powtemp; 113 for (; ; pow10 /= 10.0) { 114 int digit = value/pow10; 115 *p++ = digit + '0'; 116 value -= digit * pow10; 117 ++*decpt; 118 if (pow10 <= 10.0) 119 break; 120 } 121 } else if (value < 1.0) 122 do { 123 for (; value * sp->p10 < 10.0; *decpt -= sp->n) 124 value *= sp->p10; 125 } while (sp++->n > 1); 126 } 127 if (f_flag) 128 p_last += *decpt; 129 if (p_last >= buf) { 130 if (p_last > &buf[NDIG - 2]) 131 p_last = &buf[NDIG - 2]; 132 for (; ; ++p) { 133 if (value == 0 || p >= &buf[NMAX]) 134 *p = '0'; 135 else { 136 int intx; /* intx in [0, 9] */ 137 *p = (intx = (int)value) + '0'; 138 value = 10.0 * (value - (double)intx); 139 } 140 if (p >= p_last) { 141 p = p_last; 142 break; 143 } 144 } 145 if (*p >= '5') /* check rounding in last place + 1 */ 146 do { 147 if (p == buf) { /* rollover from 99999... */ 148 buf[0] = '1'; /* later digits are 0 */ 149 ++*decpt; 150 if (f_flag) 151 ++p_last; 152 break; 153 } 154 *p = '0'; 155 } while (++*--p > '9'); /* propagate carries left */ 156 *p_last = '\0'; 157 } 158 return (buf); 159 } 160