1 /*- 2 * Copyright (c) 2004-2008 David Schultz <das@FreeBSD.ORG> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <float.h> 31 #include <limits.h> 32 #include <math.h> 33 #include <stdint.h> 34 35 #ifdef __i386__ 36 #include <ieeefp.h> 37 #endif 38 39 #include "../stdio/floatio.h" 40 #include "fpmath.h" 41 #include "gdtoaimp.h" 42 43 #if (LDBL_MANT_DIG > DBL_MANT_DIG) 44 45 /* Strings values used by dtoa() */ 46 #define INFSTR "Infinity" 47 #define NANSTR "NaN" 48 49 #ifdef LDBL_IMPLICIT_NBIT 50 #define MANH_SIZE LDBL_MANH_SIZE 51 #else 52 #define MANH_SIZE (LDBL_MANH_SIZE - 1) 53 #endif 54 55 #if MANH_SIZE > 32 56 typedef uint64_t manh_t; 57 #else 58 typedef uint32_t manh_t; 59 #endif 60 61 #if LDBL_MANL_SIZE > 32 62 typedef uint64_t manl_t; 63 #else 64 typedef uint32_t manl_t; 65 #endif 66 67 #define LDBL_ADJ (LDBL_MAX_EXP - 2) 68 #define SIGFIGS ((LDBL_MANT_DIG + 3) / 4 + 1) 69 70 static const float one[] = { 1.0f, -1.0f }; 71 72 /* 73 * This is the long double version of __hdtoa(). 74 */ 75 char * 76 __hldtoa(long double e, const char *xdigs, int ndigits, int *decpt, int *sign, 77 char **rve) 78 { 79 union IEEEl2bits u; 80 char *s, *s0; 81 manh_t manh; 82 manl_t manl; 83 int bufsize; 84 #ifdef __i386__ 85 fp_prec_t oldprec; 86 #endif 87 88 u.e = e; 89 *sign = u.bits.sign; 90 91 switch (fpclassify(e)) { 92 case FP_NORMAL: 93 *decpt = u.bits.exp - LDBL_ADJ; 94 break; 95 case FP_ZERO: 96 *decpt = 1; 97 return (nrv_alloc("0", rve, 1)); 98 case FP_SUBNORMAL: 99 #ifdef __i386__ 100 oldprec = fpsetprec(FP_PE); 101 #endif 102 u.e *= 0x1p514L; 103 *decpt = u.bits.exp - (514 + LDBL_ADJ); 104 #ifdef __i386__ 105 fpsetprec(oldprec); 106 #endif 107 break; 108 case FP_INFINITE: 109 *decpt = INT_MAX; 110 return (nrv_alloc(INFSTR, rve, sizeof(INFSTR) - 1)); 111 default: /* FP_NAN or unrecognized */ 112 *decpt = INT_MAX; 113 return (nrv_alloc(NANSTR, rve, sizeof(NANSTR) - 1)); 114 } 115 116 /* FP_NORMAL or FP_SUBNORMAL */ 117 118 if (ndigits == 0) /* dtoa() compatibility */ 119 ndigits = 1; 120 121 /* 122 * If ndigits < 0, we are expected to auto-size, so we allocate 123 * enough space for all the digits. 124 */ 125 bufsize = (ndigits > 0) ? ndigits : SIGFIGS; 126 s0 = rv_alloc(bufsize); 127 128 /* Round to the desired number of digits. */ 129 if (SIGFIGS > ndigits && ndigits > 0) { 130 float redux = one[u.bits.sign]; 131 int offset = 4 * ndigits + LDBL_MAX_EXP - 4 - LDBL_MANT_DIG; 132 #ifdef __i386__ 133 oldprec = fpsetprec(FP_PE); 134 #endif 135 u.bits.exp = offset; 136 u.e += redux; 137 u.e -= redux; 138 *decpt += u.bits.exp - offset; 139 #ifdef __i386__ 140 fpsetprec(oldprec); 141 #endif 142 } 143 144 mask_nbit_l(u); 145 manh = u.bits.manh; 146 manl = u.bits.manl; 147 *s0 = '1'; 148 for (s = s0 + 1; s < s0 + bufsize; s++) { 149 *s = xdigs[(manh >> (MANH_SIZE - 4)) & 0xf]; 150 manh = (manh << 4) | (manl >> (LDBL_MANL_SIZE - 4)); 151 manl <<= 4; 152 } 153 154 /* If ndigits < 0, we are expected to auto-size the precision. */ 155 if (ndigits < 0) { 156 for (ndigits = SIGFIGS; s0[ndigits - 1] == '0'; ndigits--) 157 ; 158 } 159 160 s = s0 + ndigits; 161 *s = '\0'; 162 if (rve != NULL) 163 *rve = s; 164 return (s0); 165 } 166 167 #else /* (LDBL_MANT_DIG == DBL_MANT_DIG) */ 168 169 char * 170 __hldtoa(long double e, const char *xdigs, int ndigits, int *decpt, int *sign, 171 char **rve) 172 { 173 174 return (__hdtoa((double)e, xdigs, ndigits, decpt, sign, rve)); 175 } 176 177 #endif /* (LDBL_MANT_DIG == DBL_MANT_DIG) */ 178