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