_Ldtob.c (8209B)
1 #include "libultra_internal.h" 2 #include <macros.h> 3 #include <stdlib.h> 4 #include <string.h> 5 #include "printf.h" 6 7 #define BUFF_LEN 0x20 8 9 static s16 _Ldunscale(s16 *, printf_struct *); 10 static void _Genld(printf_struct *, fmt_type, fmt_type *, s16, s16); 11 12 const double pows[] = { 10e0L, 10e1L, 10e3L, 10e7L, 10e15L, 10e31L, 10e63L, 10e127L, 10e255L }; 13 14 /* float properties */ 15 #define _D0 0 16 #define _DBIAS 0x3ff 17 #define _DLONG 1 18 #define _DOFF 4 19 #define _FBIAS 0x7e 20 #define _FOFF 7 21 #define _FRND 1 22 #define _LBIAS 0x3ffe 23 #define _LOFF 15 24 /* integer properties */ 25 #define _C2 1 26 #define _CSIGN 1 27 #define _ILONG 0 28 #define _MBMAX 8 29 #define NAN 2 30 #define INF 1 31 #define FINITE -1 32 #define _DFRAC ((1 << _DOFF) - 1) 33 #define _DMASK (0x7fff & ~_DFRAC) 34 #define _DMAX ((1 << (15 - _DOFF)) - 1) 35 #define _DNAN (0x8000 | _DMAX << _DOFF | 1 << (_DOFF - 1)) 36 #define _DSIGN 0x8000 37 #if _D0 == 3 38 #define _D1 2 /* little-endian order */ 39 #define _D2 1 40 #define _D3 0 41 #else 42 #define _D1 1 /* big-endian order */ 43 #define _D2 2 44 #define _D3 3 45 #endif 46 47 void _Ldtob(printf_struct *args, fmt_type type) { 48 fmt_type buff[BUFF_LEN]; 49 fmt_type *ptr; 50 f64 val; 51 /* maybe struct? */ 52 s16 err; 53 s16 nsig; 54 s16 exp; 55 56 s32 i; 57 s32 n; 58 f64 factor; 59 s32 gen; 60 s32 j; 61 62 ptr = buff; 63 val = args->value.f64; 64 if (args->precision < 0) { 65 args->precision = 6; 66 } else { 67 if (args->precision == 0 && (type == 'g' || type == 'G')) { 68 args->precision = 1; 69 } 70 } 71 err = _Ldunscale(&exp, args); 72 if (err > 0) { 73 memcpy(args->buff, err == 2 ? "NaN" : "Inf", args->part2_len = 3); 74 return; 75 } 76 if (err == 0) { 77 nsig = 0; 78 exp = 0; 79 } else { 80 if (val < 0) { 81 val = -val; 82 } 83 exp = exp * 30103 / 0x000186A0 - 4; 84 if (exp < 0) { 85 n = (-exp + 3) & ~3; 86 exp = -n; 87 for (i = 0; n > 0; n >>= 1, i++) { 88 if ((n & 1) != 0) { 89 val *= pows[i]; 90 } 91 } 92 } else { 93 if (exp > 0) { 94 factor = 1; 95 exp &= ~3; 96 for (n = exp, i = 0; n > 0; n >>= 1, i++) { 97 if ((n & 1) != 0) { 98 factor *= pows[i]; 99 } 100 } 101 val /= factor; 102 } 103 } 104 gen = args->precision + ((type == 'f') ? exp + 10 : 6); 105 if (gen > 0x13) { 106 gen = 0x13; 107 } 108 *ptr++ = '0'; 109 while (gen > 0 && 0 < val) { 110 s32 lo = val; 111 if ((gen -= 8) > 0) { 112 val = (val - lo) * 1.0e8; 113 } 114 ptr = ptr + 8; 115 for (j = 8; lo > 0 && --j >= 0;) { 116 ldiv_t qr = ldiv(lo, 10); 117 *--ptr = qr.rem + '0'; 118 lo = qr.quot; 119 } 120 while (--j >= 0) { 121 ptr--; 122 *ptr = '0'; 123 } 124 ptr += 8; 125 } 126 127 gen = ptr - &buff[1]; 128 for (ptr = &buff[1], exp += 7; *ptr == '0'; ptr++) { 129 --gen, --exp; 130 } 131 132 nsig = args->precision + ((type == 'f') ? exp + 1 : ((type == 'e' || type == 'E') ? 1 : 0)); 133 if (gen < nsig) { 134 nsig = gen; 135 } 136 if (nsig > 0) { 137 fmt_type drop = (nsig < gen && ptr[nsig] > '4') ? '9' : '0'; 138 s32 n2; 139 140 for (n2 = nsig; ptr[--n2] == drop;) { 141 nsig--; 142 } 143 if (drop == '9') { 144 ptr[n2]++; 145 } 146 if (n2 < 0) { 147 --ptr, ++nsig, ++exp; 148 } 149 } 150 } 151 _Genld(args, type, ptr, nsig, exp); 152 } 153 154 static s16 _Ldunscale(s16 *pex, printf_struct *px) { 155 156 unsigned short *ps = (unsigned short *) px; 157 short xchar = (ps[_D0] & _DMASK) >> _DOFF; 158 if (xchar == _DMAX) { /* NaN or INF */ 159 *pex = 0; 160 return (s16)(ps[_D0] & _DFRAC || ps[_D1] || ps[_D2] || ps[_D3] ? NAN : INF); 161 } else if (0 < xchar) { 162 ps[_D0] = (ps[_D0] & ~_DMASK) | (_DBIAS << _DOFF); 163 *pex = xchar - (_DBIAS - 1); 164 return (FINITE); 165 } 166 if (0 > xchar) { 167 return NAN; 168 } else { 169 *pex = 0; 170 return (0); 171 } 172 } 173 174 static void _Genld(printf_struct *px, fmt_type code, fmt_type *p, s16 nsig, s16 xexp) { 175 const fmt_type point = '.'; 176 if (nsig <= 0) { 177 nsig = 1, 178 179 p = (fmt_type *) "0"; 180 } 181 182 if (code == 'f' 183 || ((code == 'g' || code == 'G') && (-4 <= xexp) && (xexp < px->precision))) { /* 'f' format */ 184 ++xexp; /* change to leading digit count */ 185 if (code != 'f') { /* fixup for 'g' */ 186 if (!(px->flags & FLAGS_HASH) && nsig < px->precision) { 187 px->precision = nsig; 188 } 189 if ((px->precision -= xexp) < 0) { 190 px->precision = 0; 191 } 192 } 193 if (xexp <= 0) { /* digits only to right of point */ 194 px->buff[px->part2_len++] = '0'; 195 if (0 < px->precision || px->flags & FLAGS_HASH) { 196 px->buff[px->part2_len++] = point; 197 } 198 if (px->precision < -xexp) { 199 xexp = -px->precision; 200 } 201 px->num_mid_zeros = -xexp; 202 px->precision += xexp; 203 if (px->precision < nsig) { 204 nsig = px->precision; 205 } 206 memcpy(&px->buff[px->part2_len], p, px->part3_len = nsig); 207 px->num_trailing_zeros = px->precision - nsig; 208 } else if (nsig < xexp) { /* zeros before point */ 209 memcpy(&px->buff[px->part2_len], p, nsig); 210 px->part2_len += nsig; 211 px->num_mid_zeros = xexp - nsig; 212 if (0 < px->precision || px->flags & FLAGS_HASH) { 213 px->buff[px->part2_len] = point, ++px->part3_len; 214 } 215 px->num_trailing_zeros = px->precision; 216 } else { /* enough digits before point */ 217 memcpy(&px->buff[px->part2_len], p, xexp); 218 px->part2_len += xexp; 219 nsig -= xexp; 220 if (0 < px->precision || px->flags & FLAGS_HASH) { 221 px->buff[px->part2_len++] = point; 222 } 223 if (px->precision < nsig) { 224 nsig = px->precision; 225 } 226 memcpy(&px->buff[px->part2_len], p + xexp, nsig); 227 px->part2_len += nsig; 228 px->num_mid_zeros = px->precision - nsig; 229 } 230 } else { /* 'e' format */ 231 if (code == 'g' || code == 'G') { /* fixup for 'g' */ 232 if (nsig < px->precision) { 233 px->precision = nsig; 234 } 235 if (--px->precision < 0) { 236 px->precision = 0; 237 } 238 code = code == 'g' ? 'e' : 'E'; 239 } 240 px->buff[px->part2_len++] = *p++; 241 if (0 < px->precision || px->flags & FLAGS_HASH) { 242 px->buff[px->part2_len++] = point; 243 } 244 if (0 < px->precision) { /* put fraction digits */ 245 if (px->precision < --nsig) { 246 nsig = px->precision; 247 } 248 memcpy(&px->buff[px->part2_len], p, nsig); 249 px->part2_len += nsig; 250 px->num_mid_zeros = px->precision - nsig; 251 } 252 p = (fmt_type *) &px->buff[px->part2_len]; /* put exponent */ 253 *p++ = code; 254 if (0 <= xexp) { 255 *p++ = '+'; 256 } else { /* negative exponent */ 257 *p++ = '-'; 258 xexp = -xexp; 259 } 260 if (100 <= xexp) { /* put oversize exponent */ 261 if (1000 <= xexp) { 262 *p++ = xexp / 1000 + '0', xexp %= 1000; 263 } 264 *p++ = xexp / 100 + '0', xexp %= 100; 265 } 266 *p++ = xexp / 10 + '0', xexp %= 10; 267 *p++ = xexp + '0'; 268 px->part3_len = p - (fmt_type *) &px->buff[px->part2_len]; 269 } 270 if ((px->flags & (FLAGS_ZERO | FLAGS_MINUS)) == FLAGS_ZERO) { /* pad with leading zeros */ 271 int n = 272 px->part1_len + px->part2_len + px->num_mid_zeros + px->part3_len + px->num_trailing_zeros; 273 274 if (n < px->width) { 275 px->num_leading_zeros = px->width - n; 276 } 277 } 278 }