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 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include "lint.h" 30 #include "base_conversion.h" 31 #include <sys/types.h> 32 #include "libc.h" 33 34 char * 35 fconvert(double arg, int ndigits, int *decpt, int *sign, char *buf) 36 { 37 decimal_mode dm; 38 decimal_record dr; 39 fp_exception_field_type ef; 40 int i; 41 42 #if defined(__sparc) 43 dm.rd = _QgetRD(); 44 #elif defined(__i386) || defined(__amd64) 45 dm.rd = __xgetRD(); 46 #else 47 #error Unknown architecture 48 #endif 49 dm.df = fixed_form; /* F format. */ 50 if (ndigits <= -DECIMAL_STRING_LENGTH) 51 ndigits = -DECIMAL_STRING_LENGTH + 1; 52 else if (ndigits >= DECIMAL_STRING_LENGTH) 53 ndigits = DECIMAL_STRING_LENGTH - 1; 54 dm.ndigits = ndigits; /* Number of digits after point. */ 55 double_to_decimal(&arg, &dm, &dr, &ef); 56 *sign = dr.sign; 57 switch (dr.fpclass) { 58 case fp_normal: 59 case fp_subnormal: 60 *decpt = dr.exponent + dr.ndigits; 61 for (i = 0; i < dr.ndigits; i++) 62 buf[i] = dr.ds[i]; 63 /* 64 * Pad with zeroes if we didn't get all the digits 65 * we asked for. 66 */ 67 if (ndigits > 0 && dr.exponent > -ndigits) { 68 while (i < dr.ndigits + dr.exponent + ndigits) 69 buf[i++] = '0'; 70 } 71 buf[i] = 0; 72 break; 73 case fp_zero: 74 *decpt = 0; 75 buf[0] = '0'; 76 for (i = 1; i < ndigits; i++) 77 buf[i] = '0'; 78 buf[i] = 0; 79 break; 80 default: 81 *decpt = 0; 82 __infnanstring(dr.fpclass, ndigits, buf); 83 break; 84 } 85 return (buf); 86 } 87 88 char * 89 sfconvert(single *arg, int ndigits, int *decpt, int *sign, char *buf) 90 { 91 decimal_mode dm; 92 decimal_record dr; 93 fp_exception_field_type ef; 94 int i; 95 96 #if defined(__sparc) 97 dm.rd = _QgetRD(); 98 #elif defined(__i386) || defined(__amd64) 99 dm.rd = __xgetRD(); 100 #else 101 #error Unknown architecture 102 #endif 103 dm.df = fixed_form; /* F format. */ 104 if (ndigits <= -DECIMAL_STRING_LENGTH) 105 ndigits = -DECIMAL_STRING_LENGTH + 1; 106 else if (ndigits >= DECIMAL_STRING_LENGTH) 107 ndigits = DECIMAL_STRING_LENGTH - 1; 108 dm.ndigits = ndigits; /* Number of digits after point. */ 109 single_to_decimal(arg, &dm, &dr, &ef); 110 *sign = dr.sign; 111 switch (dr.fpclass) { 112 case fp_normal: 113 case fp_subnormal: 114 *decpt = dr.exponent + dr.ndigits; 115 for (i = 0; i < dr.ndigits; i++) 116 buf[i] = dr.ds[i]; 117 /* 118 * Pad with zeroes if we didn't get all the digits 119 * we asked for. 120 */ 121 if (ndigits > 0 && dr.exponent > -ndigits) { 122 while (i < dr.ndigits + dr.exponent + ndigits) 123 buf[i++] = '0'; 124 } 125 buf[i] = 0; 126 break; 127 case fp_zero: 128 *decpt = 0; 129 buf[0] = '0'; 130 for (i = 1; i < ndigits; i++) 131 buf[i] = '0'; 132 buf[i] = 0; 133 break; 134 default: 135 *decpt = 0; 136 __infnanstring(dr.fpclass, ndigits, buf); 137 break; 138 } 139 return (buf); 140 } 141 142 char * 143 qfconvert(quadruple *arg, int ndigits, int *decpt, int *sign, char *buf) 144 { 145 decimal_mode dm; 146 decimal_record dr; 147 fp_exception_field_type ef; 148 int i; 149 150 #if defined(__sparc) 151 dm.rd = _QgetRD(); 152 #elif defined(__i386) || defined(__amd64) 153 dm.rd = __xgetRD(); 154 #else 155 #error Unknown architecture 156 #endif 157 dm.df = fixed_form; /* F format. */ 158 if (ndigits <= -DECIMAL_STRING_LENGTH) 159 ndigits = -DECIMAL_STRING_LENGTH + 1; 160 else if (ndigits >= DECIMAL_STRING_LENGTH) 161 ndigits = DECIMAL_STRING_LENGTH - 1; 162 dm.ndigits = ndigits; /* Number of digits after point. */ 163 #if defined(__sparc) 164 quadruple_to_decimal(arg, &dm, &dr, &ef); 165 #elif defined(__i386) || defined(__amd64) 166 extended_to_decimal((extended *)arg, &dm, &dr, &ef); 167 #else 168 #error Unknown architecture 169 #endif 170 *sign = dr.sign; 171 if (ef & (1 << fp_overflow)) { 172 /* 173 * *_to_decimal raises overflow whenever dr.ds isn't large 174 * enough to hold all the digits requested. For float and 175 * double, this can only happen when the requested format 176 * would require trailing zeroes, in which case fconvert 177 * and sfconvert just add them. For long double, the arg- 178 * ument might be large enough that even the nonzero digits 179 * would overflow dr.ds, so we punt instead. (We could 180 * distinguish these two cases, but it doesn't seem worth 181 * changing things now, particularly since no real appli- 182 * cation prints floating point numbers to 500 digits.) 183 */ 184 *decpt = 0; 185 buf[0] = 0; 186 return (buf); 187 } 188 switch (dr.fpclass) { 189 case fp_normal: 190 case fp_subnormal: 191 *decpt = dr.exponent + dr.ndigits; 192 for (i = 0; i < dr.ndigits; i++) 193 buf[i] = dr.ds[i]; 194 buf[i] = 0; 195 break; 196 case fp_zero: 197 *decpt = 0; 198 buf[0] = '0'; 199 for (i = 1; i < ndigits; i++) 200 buf[i] = '0'; 201 buf[i] = 0; 202 break; 203 default: 204 *decpt = 0; 205 __infnanstring(dr.fpclass, ndigits, buf); 206 break; 207 } 208 return (buf); 209 } 210