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