1 #include <precomp.h> 2 3 // From Wine msvcrt.h 4 typedef struct {ULONG x80[3];} MSVCRT__LDOUBLE; /* Intel 80 bit FP format has sizeof() 12 */ 5 enum fpmod { 6 FP_ROUND_ZERO, /* only used when dropped part contains only zeros */ 7 FP_ROUND_DOWN, 8 FP_ROUND_EVEN, 9 FP_ROUND_UP, 10 FP_VAL_INFINITY, 11 FP_VAL_NAN 12 }; 13 struct fpnum { 14 int sign; 15 int exp; 16 ULONGLONG m; 17 enum fpmod mod; 18 }; 19 20 // From wine bnum.h 21 #define EXP_BITS 11 22 #define MANT_BITS 53 23 24 int fpnum_double(struct fpnum *fp, double *d) 25 { 26 ULONGLONG bits = 0; 27 28 if (fp->mod == FP_VAL_INFINITY) 29 { 30 *d = fp->sign * INFINITY; 31 return 0; 32 } 33 34 if (fp->mod == FP_VAL_NAN) 35 { 36 bits = ~0; 37 if (fp->sign == 1) 38 bits &= ~((ULONGLONG)1 << (MANT_BITS + EXP_BITS - 1)); 39 *d = *(double*)&bits; 40 return 0; 41 } 42 43 TRACE("%c %#I64x *2^%d (round %d)\n", fp->sign == -1 ? '-' : '+', 44 fp->m, fp->exp, fp->mod); 45 if (!fp->m) 46 { 47 *d = fp->sign * 0.0; 48 return 0; 49 } 50 51 /* make sure that we don't overflow modifying exponent */ 52 if (fp->exp > 1<<EXP_BITS) 53 { 54 *d = fp->sign * INFINITY; 55 return ERANGE; 56 } 57 if (fp->exp < -(1<<EXP_BITS)) 58 { 59 *d = fp->sign * 0.0; 60 return ERANGE; 61 } 62 fp->exp += MANT_BITS - 1; 63 64 /* normalize mantissa */ 65 while(fp->m < (ULONGLONG)1 << (MANT_BITS-1)) 66 { 67 fp->m <<= 1; 68 fp->exp--; 69 } 70 while(fp->m >= (ULONGLONG)1 << MANT_BITS) 71 { 72 if (fp->m & 1 || fp->mod != FP_ROUND_ZERO) 73 { 74 if (!(fp->m & 1)) fp->mod = FP_ROUND_DOWN; 75 else if(fp->mod == FP_ROUND_ZERO) fp->mod = FP_ROUND_EVEN; 76 else fp->mod = FP_ROUND_UP; 77 } 78 fp->m >>= 1; 79 fp->exp++; 80 } 81 fp->exp += (1 << (EXP_BITS-1)) - 1; 82 83 /* handle subnormals */ 84 if (fp->exp <= 0) 85 { 86 if (fp->m & 1 && fp->mod == FP_ROUND_ZERO) fp->mod = FP_ROUND_EVEN; 87 else if (fp->m & 1) fp->mod = FP_ROUND_UP; 88 else if (fp->mod != FP_ROUND_ZERO) fp->mod = FP_ROUND_DOWN; 89 fp->m >>= 1; 90 } 91 while(fp->m && fp->exp<0) 92 { 93 if (fp->m & 1 && fp->mod == FP_ROUND_ZERO) fp->mod = FP_ROUND_EVEN; 94 else if (fp->m & 1) fp->mod = FP_ROUND_UP; 95 else if (fp->mod != FP_ROUND_ZERO) fp->mod = FP_ROUND_DOWN; 96 fp->m >>= 1; 97 fp->exp++; 98 } 99 100 /* round mantissa */ 101 if (fp->mod == FP_ROUND_UP || (fp->mod == FP_ROUND_EVEN && fp->m & 1)) 102 { 103 fp->m++; 104 105 /* handle subnormal that falls into regular range due to rounding */ 106 if (fp->m == (ULONGLONG)1 << (MANT_BITS - 1)) 107 { 108 fp->exp++; 109 } 110 else if (fp->m >= (ULONGLONG)1 << MANT_BITS) 111 { 112 fp->exp++; 113 fp->m >>= 1; 114 } 115 } 116 117 if (fp->exp >= (1<<EXP_BITS)-1) 118 { 119 *d = fp->sign * INFINITY; 120 return ERANGE; 121 } 122 if (!fp->m || fp->exp < 0) 123 { 124 *d = fp->sign * 0.0; 125 return ERANGE; 126 } 127 128 if (fp->sign == -1) 129 bits |= (ULONGLONG)1 << (MANT_BITS + EXP_BITS - 1); 130 bits |= (ULONGLONG)fp->exp << (MANT_BITS - 1); 131 bits |= fp->m & (((ULONGLONG)1 << (MANT_BITS - 1)) - 1); 132 133 TRACE("returning %#I64x\n", bits); 134 *d = *(double*)&bits; 135 return 0; 136 } 137 138 #define I10_OUTPUT_MAX_PREC 21 139 /* Internal structure used by $I10_OUTPUT */ 140 struct _I10_OUTPUT_DATA { 141 short pos; 142 char sign; 143 BYTE len; 144 char str[I10_OUTPUT_MAX_PREC+1]; /* add space for '\0' */ 145 }; 146 147 /********************************************************************* 148 * $I10_OUTPUT (MSVCRT.@) 149 * ld80 - long double (Intel 80 bit FP in 12 bytes) to be printed to data 150 * prec - precision of part, we're interested in 151 * flag - 0 for first prec digits, 1 for fractional part 152 * data - data to be populated 153 * 154 * return value 155 * 0 if given double is NaN or INF 156 * 1 otherwise 157 * 158 * FIXME 159 * Native sets last byte of data->str to '0' or '9', I don't know what 160 * it means. Current implementation sets it always to '0'. 161 */ 162 int CDECL I10_OUTPUT(MSVCRT__LDOUBLE ld80, int prec, int flag, struct _I10_OUTPUT_DATA *data) 163 { 164 struct fpnum num; 165 double d; 166 char format[8]; 167 char buf[I10_OUTPUT_MAX_PREC+9]; /* 9 = strlen("0.e+0000") + '\0' */ 168 char *p; 169 170 if ((ld80.x80[2] & 0x7fff) == 0x7fff) 171 { 172 if (ld80.x80[0] == 0 && ld80.x80[1] == 0x80000000) 173 strcpy( data->str, "1#INF" ); 174 else 175 strcpy( data->str, (ld80.x80[1] & 0x40000000) ? "1#QNAN" : "1#SNAN" ); 176 data->pos = 1; 177 data->sign = (ld80.x80[2] & 0x8000) ? '-' : ' '; 178 data->len = (BYTE)strlen(data->str); 179 return 0; 180 } 181 182 num.sign = (ld80.x80[2] & 0x8000) ? -1 : 1; 183 num.exp = (ld80.x80[2] & 0x7fff) - 0x3fff - 63; 184 num.m = ld80.x80[0] | ((ULONGLONG)ld80.x80[1] << 32); 185 num.mod = FP_ROUND_EVEN; 186 fpnum_double( &num, &d ); 187 TRACE("(%lf %d %x %p)\n", d, prec, flag, data); 188 189 if(d<0) { 190 data->sign = '-'; 191 d = -d; 192 } else 193 data->sign = ' '; 194 195 if(flag&1) { 196 int exp = 1 + floor(log10(d)); 197 198 prec += exp; 199 if(exp < 0) 200 prec--; 201 } 202 prec--; 203 204 if(prec+1 > I10_OUTPUT_MAX_PREC) 205 prec = I10_OUTPUT_MAX_PREC-1; 206 else if(prec < 0) { 207 d = 0.0; 208 prec = 0; 209 } 210 211 sprintf_s(format, sizeof(format), "%%.%dle", prec); 212 sprintf_s(buf, sizeof(buf), format, d); 213 214 buf[1] = buf[0]; 215 data->pos = atoi(buf+prec+3); 216 if(buf[1] != '0') 217 data->pos++; 218 219 for(p = buf+prec+1; p>buf+1 && *p=='0'; p--); 220 data->len = p-buf; 221 222 memcpy(data->str, buf+1, data->len); 223 data->str[data->len] = '\0'; 224 225 if(buf[1]!='0' && prec-data->len+1>0) 226 memcpy(data->str+data->len+1, buf+data->len+1, prec-data->len+1); 227 228 return 1; 229 } 230 #undef I10_OUTPUT_MAX_PREC 231