Mercurial
comparison third_party/luajit/src/lj_strfmt_num.c @ 178:94705b5986b3
[ThirdParty] Added WRK and luajit for load testing.
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Thu, 22 Jan 2026 20:10:30 -0800 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 177:24fe8ff94056 | 178:94705b5986b3 |
|---|---|
| 1 /* | |
| 2 ** String formatting for floating-point numbers. | |
| 3 ** Copyright (C) 2005-2023 Mike Pall. See Copyright Notice in luajit.h | |
| 4 ** Contributed by Peter Cawley. | |
| 5 */ | |
| 6 | |
| 7 #include <stdio.h> | |
| 8 | |
| 9 #define lj_strfmt_num_c | |
| 10 #define LUA_CORE | |
| 11 | |
| 12 #include "lj_obj.h" | |
| 13 #include "lj_buf.h" | |
| 14 #include "lj_str.h" | |
| 15 #include "lj_strfmt.h" | |
| 16 | |
| 17 /* -- Precomputed tables -------------------------------------------------- */ | |
| 18 | |
| 19 /* Rescale factors to push the exponent of a number towards zero. */ | |
| 20 #define RESCALE_EXPONENTS(P, N) \ | |
| 21 P(308), P(289), P(270), P(250), P(231), P(212), P(193), P(173), P(154), \ | |
| 22 P(135), P(115), P(96), P(77), P(58), P(38), P(0), P(0), P(0), N(39), N(58), \ | |
| 23 N(77), N(96), N(116), N(135), N(154), N(174), N(193), N(212), N(231), \ | |
| 24 N(251), N(270), N(289) | |
| 25 | |
| 26 #define ONE_E_P(X) 1e+0 ## X | |
| 27 #define ONE_E_N(X) 1e-0 ## X | |
| 28 static const int16_t rescale_e[] = { RESCALE_EXPONENTS(-, +) }; | |
| 29 static const double rescale_n[] = { RESCALE_EXPONENTS(ONE_E_P, ONE_E_N) }; | |
| 30 #undef ONE_E_N | |
| 31 #undef ONE_E_P | |
| 32 | |
| 33 /* | |
| 34 ** For p in range -70 through 57, this table encodes pairs (m, e) such that | |
| 35 ** 4*2^p <= (uint8_t)m*10^e, and is the smallest value for which this holds. | |
| 36 */ | |
| 37 static const int8_t four_ulp_m_e[] = { | |
| 38 34, -21, 68, -21, 14, -20, 28, -20, 55, -20, 2, -19, 3, -19, 5, -19, 9, -19, | |
| 39 -82, -18, 35, -18, 7, -17, -117, -17, 28, -17, 56, -17, 112, -16, -33, -16, | |
| 40 45, -16, 89, -16, -78, -15, 36, -15, 72, -15, -113, -14, 29, -14, 57, -14, | |
| 41 114, -13, -28, -13, 46, -13, 91, -12, -74, -12, 37, -12, 73, -12, 15, -11, 3, | |
| 42 -11, 59, -11, 2, -10, 3, -10, 5, -10, 1, -9, -69, -9, 38, -9, 75, -9, 15, -7, | |
| 43 3, -7, 6, -7, 12, -6, -17, -7, 48, -7, 96, -7, -65, -6, 39, -6, 77, -6, -103, | |
| 44 -5, 31, -5, 62, -5, 123, -4, -11, -4, 49, -4, 98, -4, -60, -3, 4, -2, 79, -3, | |
| 45 16, -2, 32, -2, 63, -2, 2, -1, 25, 0, 5, 1, 1, 2, 2, 2, 4, 2, 8, 2, 16, 2, | |
| 46 32, 2, 64, 2, -128, 2, 26, 2, 52, 2, 103, 3, -51, 3, 41, 4, 82, 4, -92, 4, | |
| 47 33, 4, 66, 4, -124, 5, 27, 5, 53, 5, 105, 6, 21, 6, 42, 6, 84, 6, 17, 7, 34, | |
| 48 7, 68, 7, 2, 8, 3, 8, 6, 8, 108, 9, -41, 9, 43, 10, 86, 9, -84, 10, 35, 10, | |
| 49 69, 10, -118, 11, 28, 11, 55, 12, 11, 13, 22, 13, 44, 13, 88, 13, -80, 13, | |
| 50 36, 13, 71, 13, -115, 14, 29, 14, 57, 14, 113, 15, -30, 15, 46, 15, 91, 15, | |
| 51 19, 16, 37, 16, 73, 16, 2, 17, 3, 17, 6, 17 | |
| 52 }; | |
| 53 | |
| 54 /* min(2^32-1, 10^e-1) for e in range 0 through 10 */ | |
| 55 static uint32_t ndigits_dec_threshold[] = { | |
| 56 0, 9U, 99U, 999U, 9999U, 99999U, 999999U, | |
| 57 9999999U, 99999999U, 999999999U, 0xffffffffU | |
| 58 }; | |
| 59 | |
| 60 /* -- Helper functions ---------------------------------------------------- */ | |
| 61 | |
| 62 /* Compute the number of digits in the decimal representation of x. */ | |
| 63 static MSize ndigits_dec(uint32_t x) | |
| 64 { | |
| 65 MSize t = ((lj_fls(x | 1) * 77) >> 8) + 1; /* 2^8/77 is roughly log2(10) */ | |
| 66 return t + (x > ndigits_dec_threshold[t]); | |
| 67 } | |
| 68 | |
| 69 #define WINT_R(x, sh, sc) \ | |
| 70 { uint32_t d = (x*(((1<<sh)+sc-1)/sc))>>sh; x -= d*sc; *p++ = (char)('0'+d); } | |
| 71 | |
| 72 /* Write 9-digit unsigned integer to buffer. */ | |
| 73 static char *lj_strfmt_wuint9(char *p, uint32_t u) | |
| 74 { | |
| 75 uint32_t v = u / 10000, w; | |
| 76 u -= v * 10000; | |
| 77 w = v / 10000; | |
| 78 v -= w * 10000; | |
| 79 *p++ = (char)('0'+w); | |
| 80 WINT_R(v, 23, 1000) | |
| 81 WINT_R(v, 12, 100) | |
| 82 WINT_R(v, 10, 10) | |
| 83 *p++ = (char)('0'+v); | |
| 84 WINT_R(u, 23, 1000) | |
| 85 WINT_R(u, 12, 100) | |
| 86 WINT_R(u, 10, 10) | |
| 87 *p++ = (char)('0'+u); | |
| 88 return p; | |
| 89 } | |
| 90 #undef WINT_R | |
| 91 | |
| 92 /* -- Extended precision arithmetic --------------------------------------- */ | |
| 93 | |
| 94 /* | |
| 95 ** The "nd" format is a fixed-precision decimal representation for numbers. It | |
| 96 ** consists of up to 64 uint32_t values, with each uint32_t storing a value | |
| 97 ** in the range [0, 1e9). A number in "nd" format consists of three variables: | |
| 98 ** | |
| 99 ** uint32_t nd[64]; | |
| 100 ** uint32_t ndlo; | |
| 101 ** uint32_t ndhi; | |
| 102 ** | |
| 103 ** The integral part of the number is stored in nd[0 ... ndhi], the value of | |
| 104 ** which is sum{i in [0, ndhi] | nd[i] * 10^(9*i)}. If the fractional part of | |
| 105 ** the number is zero, ndlo is zero. Otherwise, the fractional part is stored | |
| 106 ** in nd[ndlo ... 63], the value of which is taken to be | |
| 107 ** sum{i in [ndlo, 63] | nd[i] * 10^(9*(i-64))}. | |
| 108 ** | |
| 109 ** If the array part had 128 elements rather than 64, then every double would | |
| 110 ** have an exact representation in "nd" format. With 64 elements, all integral | |
| 111 ** doubles have an exact representation, and all non-integral doubles have | |
| 112 ** enough digits to make both %.99e and %.99f do the right thing. | |
| 113 */ | |
| 114 | |
| 115 #if LJ_64 | |
| 116 #define ND_MUL2K_MAX_SHIFT 29 | |
| 117 #define ND_MUL2K_DIV1E9(val) ((uint32_t)((val) / 1000000000)) | |
| 118 #else | |
| 119 #define ND_MUL2K_MAX_SHIFT 11 | |
| 120 #define ND_MUL2K_DIV1E9(val) ((uint32_t)((val) >> 9) / 1953125) | |
| 121 #endif | |
| 122 | |
| 123 /* Multiply nd by 2^k and add carry_in (ndlo is assumed to be zero). */ | |
| 124 static uint32_t nd_mul2k(uint32_t* nd, uint32_t ndhi, uint32_t k, | |
| 125 uint32_t carry_in, SFormat sf) | |
| 126 { | |
| 127 uint32_t i, ndlo = 0, start = 1; | |
| 128 /* Performance hacks. */ | |
| 129 if (k > ND_MUL2K_MAX_SHIFT*2 && STRFMT_FP(sf) != STRFMT_FP(STRFMT_T_FP_F)) { | |
| 130 start = ndhi - (STRFMT_PREC(sf) + 17) / 8; | |
| 131 } | |
| 132 /* Real logic. */ | |
| 133 while (k >= ND_MUL2K_MAX_SHIFT) { | |
| 134 for (i = ndlo; i <= ndhi; i++) { | |
| 135 uint64_t val = ((uint64_t)nd[i] << ND_MUL2K_MAX_SHIFT) | carry_in; | |
| 136 carry_in = ND_MUL2K_DIV1E9(val); | |
| 137 nd[i] = (uint32_t)val - carry_in * 1000000000; | |
| 138 } | |
| 139 if (carry_in) { | |
| 140 nd[++ndhi] = carry_in; carry_in = 0; | |
| 141 if (start++ == ndlo) ++ndlo; | |
| 142 } | |
| 143 k -= ND_MUL2K_MAX_SHIFT; | |
| 144 } | |
| 145 if (k) { | |
| 146 for (i = ndlo; i <= ndhi; i++) { | |
| 147 uint64_t val = ((uint64_t)nd[i] << k) | carry_in; | |
| 148 carry_in = ND_MUL2K_DIV1E9(val); | |
| 149 nd[i] = (uint32_t)val - carry_in * 1000000000; | |
| 150 } | |
| 151 if (carry_in) nd[++ndhi] = carry_in; | |
| 152 } | |
| 153 return ndhi; | |
| 154 } | |
| 155 | |
| 156 /* Divide nd by 2^k (ndlo is assumed to be zero). */ | |
| 157 static uint32_t nd_div2k(uint32_t* nd, uint32_t ndhi, uint32_t k, SFormat sf) | |
| 158 { | |
| 159 uint32_t ndlo = 0, stop1 = ~0, stop2 = ~0; | |
| 160 /* Performance hacks. */ | |
| 161 if (!ndhi) { | |
| 162 if (!nd[0]) { | |
| 163 return 0; | |
| 164 } else { | |
| 165 uint32_t s = lj_ffs(nd[0]); | |
| 166 if (s >= k) { nd[0] >>= k; return 0; } | |
| 167 nd[0] >>= s; k -= s; | |
| 168 } | |
| 169 } | |
| 170 if (k > 18) { | |
| 171 if (STRFMT_FP(sf) == STRFMT_FP(STRFMT_T_FP_F)) { | |
| 172 stop1 = 63 - (int32_t)STRFMT_PREC(sf) / 9; | |
| 173 } else { | |
| 174 int32_t floorlog2 = ndhi * 29 + lj_fls(nd[ndhi]) - k; | |
| 175 int32_t floorlog10 = (int32_t)(floorlog2 * 0.30102999566398114); | |
| 176 stop1 = 62 + (floorlog10 - (int32_t)STRFMT_PREC(sf)) / 9; | |
| 177 stop2 = 61 + ndhi - (int32_t)STRFMT_PREC(sf) / 8; | |
| 178 } | |
| 179 } | |
| 180 /* Real logic. */ | |
| 181 while (k >= 9) { | |
| 182 uint32_t i = ndhi, carry = 0; | |
| 183 for (;;) { | |
| 184 uint32_t val = nd[i]; | |
| 185 nd[i] = (val >> 9) + carry; | |
| 186 carry = (val & 0x1ff) * 1953125; | |
| 187 if (i == ndlo) break; | |
| 188 i = (i - 1) & 0x3f; | |
| 189 } | |
| 190 if (ndlo != stop1 && ndlo != stop2) { | |
| 191 if (carry) { ndlo = (ndlo - 1) & 0x3f; nd[ndlo] = carry; } | |
| 192 if (!nd[ndhi]) { ndhi = (ndhi - 1) & 0x3f; stop2--; } | |
| 193 } else if (!nd[ndhi]) { | |
| 194 if (ndhi != ndlo) { ndhi = (ndhi - 1) & 0x3f; stop2--; } | |
| 195 else return ndlo; | |
| 196 } | |
| 197 k -= 9; | |
| 198 } | |
| 199 if (k) { | |
| 200 uint32_t mask = (1U << k) - 1, mul = 1000000000 >> k, i = ndhi, carry = 0; | |
| 201 for (;;) { | |
| 202 uint32_t val = nd[i]; | |
| 203 nd[i] = (val >> k) + carry; | |
| 204 carry = (val & mask) * mul; | |
| 205 if (i == ndlo) break; | |
| 206 i = (i - 1) & 0x3f; | |
| 207 } | |
| 208 if (carry) { ndlo = (ndlo - 1) & 0x3f; nd[ndlo] = carry; } | |
| 209 } | |
| 210 return ndlo; | |
| 211 } | |
| 212 | |
| 213 /* Add m*10^e to nd (assumes ndlo <= e/9 <= ndhi and 0 <= m <= 9). */ | |
| 214 static uint32_t nd_add_m10e(uint32_t* nd, uint32_t ndhi, uint8_t m, int32_t e) | |
| 215 { | |
| 216 uint32_t i, carry; | |
| 217 if (e >= 0) { | |
| 218 i = (uint32_t)e/9; | |
| 219 carry = m * (ndigits_dec_threshold[e - (int32_t)i*9] + 1); | |
| 220 } else { | |
| 221 int32_t f = (e-8)/9; | |
| 222 i = (uint32_t)(64 + f); | |
| 223 carry = m * (ndigits_dec_threshold[e - f*9] + 1); | |
| 224 } | |
| 225 for (;;) { | |
| 226 uint32_t val = nd[i] + carry; | |
| 227 if (LJ_UNLIKELY(val >= 1000000000)) { | |
| 228 val -= 1000000000; | |
| 229 nd[i] = val; | |
| 230 if (LJ_UNLIKELY(i == ndhi)) { | |
| 231 ndhi = (ndhi + 1) & 0x3f; | |
| 232 nd[ndhi] = 1; | |
| 233 break; | |
| 234 } | |
| 235 carry = 1; | |
| 236 i = (i + 1) & 0x3f; | |
| 237 } else { | |
| 238 nd[i] = val; | |
| 239 break; | |
| 240 } | |
| 241 } | |
| 242 return ndhi; | |
| 243 } | |
| 244 | |
| 245 /* Test whether two "nd" values are equal in their most significant digits. */ | |
| 246 static int nd_similar(uint32_t* nd, uint32_t ndhi, uint32_t* ref, MSize hilen, | |
| 247 MSize prec) | |
| 248 { | |
| 249 char nd9[9], ref9[9]; | |
| 250 if (hilen <= prec) { | |
| 251 if (LJ_UNLIKELY(nd[ndhi] != *ref)) return 0; | |
| 252 prec -= hilen; ref--; ndhi = (ndhi - 1) & 0x3f; | |
| 253 if (prec >= 9) { | |
| 254 if (LJ_UNLIKELY(nd[ndhi] != *ref)) return 0; | |
| 255 prec -= 9; ref--; ndhi = (ndhi - 1) & 0x3f; | |
| 256 } | |
| 257 } else { | |
| 258 prec -= hilen - 9; | |
| 259 } | |
| 260 lj_assertX(prec < 9, "bad precision %d", prec); | |
| 261 lj_strfmt_wuint9(nd9, nd[ndhi]); | |
| 262 lj_strfmt_wuint9(ref9, *ref); | |
| 263 return !memcmp(nd9, ref9, prec) && (nd9[prec] < '5') == (ref9[prec] < '5'); | |
| 264 } | |
| 265 | |
| 266 /* -- Formatted conversions to buffer ------------------------------------- */ | |
| 267 | |
| 268 /* Write formatted floating-point number to either sb or p. */ | |
| 269 static char *lj_strfmt_wfnum(SBuf *sb, SFormat sf, lua_Number n, char *p) | |
| 270 { | |
| 271 MSize width = STRFMT_WIDTH(sf), prec = STRFMT_PREC(sf), len; | |
| 272 TValue t; | |
| 273 t.n = n; | |
| 274 if (LJ_UNLIKELY((t.u32.hi << 1) >= 0xffe00000)) { | |
| 275 /* Handle non-finite values uniformly for %a, %e, %f, %g. */ | |
| 276 int prefix = 0, ch = (sf & STRFMT_F_UPPER) ? 0x202020 : 0; | |
| 277 if (((t.u32.hi & 0x000fffff) | t.u32.lo) != 0) { | |
| 278 ch ^= ('n' << 16) | ('a' << 8) | 'n'; | |
| 279 if ((sf & STRFMT_F_SPACE)) prefix = ' '; | |
| 280 } else { | |
| 281 ch ^= ('i' << 16) | ('n' << 8) | 'f'; | |
| 282 if ((t.u32.hi & 0x80000000)) prefix = '-'; | |
| 283 else if ((sf & STRFMT_F_PLUS)) prefix = '+'; | |
| 284 else if ((sf & STRFMT_F_SPACE)) prefix = ' '; | |
| 285 } | |
| 286 len = 3 + (prefix != 0); | |
| 287 if (!p) p = lj_buf_more(sb, width > len ? width : len); | |
| 288 if (!(sf & STRFMT_F_LEFT)) while (width-- > len) *p++ = ' '; | |
| 289 if (prefix) *p++ = prefix; | |
| 290 *p++ = (char)(ch >> 16); *p++ = (char)(ch >> 8); *p++ = (char)ch; | |
| 291 } else if (STRFMT_FP(sf) == STRFMT_FP(STRFMT_T_FP_A)) { | |
| 292 /* %a */ | |
| 293 const char *hexdig = (sf & STRFMT_F_UPPER) ? "0123456789ABCDEFPX" | |
| 294 : "0123456789abcdefpx"; | |
| 295 int32_t e = (t.u32.hi >> 20) & 0x7ff; | |
| 296 char prefix = 0, eprefix = '+'; | |
| 297 if (t.u32.hi & 0x80000000) prefix = '-'; | |
| 298 else if ((sf & STRFMT_F_PLUS)) prefix = '+'; | |
| 299 else if ((sf & STRFMT_F_SPACE)) prefix = ' '; | |
| 300 t.u32.hi &= 0xfffff; | |
| 301 if (e) { | |
| 302 t.u32.hi |= 0x100000; | |
| 303 e -= 1023; | |
| 304 } else if (t.u32.lo | t.u32.hi) { | |
| 305 /* Non-zero denormal - normalise it. */ | |
| 306 uint32_t shift = t.u32.hi ? 20-lj_fls(t.u32.hi) : 52-lj_fls(t.u32.lo); | |
| 307 e = -1022 - shift; | |
| 308 t.u64 <<= shift; | |
| 309 } | |
| 310 /* abs(n) == t.u64 * 2^(e - 52) */ | |
| 311 /* If n != 0, bit 52 of t.u64 is set, and is the highest set bit. */ | |
| 312 if ((int32_t)prec < 0) { | |
| 313 /* Default precision: use smallest precision giving exact result. */ | |
| 314 prec = t.u32.lo ? 13-lj_ffs(t.u32.lo)/4 : 5-lj_ffs(t.u32.hi|0x100000)/4; | |
| 315 } else if (prec < 13) { | |
| 316 /* Precision is sufficiently low as to maybe require rounding. */ | |
| 317 t.u64 += (((uint64_t)1) << (51 - prec*4)); | |
| 318 } | |
| 319 if (e < 0) { | |
| 320 eprefix = '-'; | |
| 321 e = -e; | |
| 322 } | |
| 323 len = 5 + ndigits_dec((uint32_t)e) + prec + (prefix != 0) | |
| 324 + ((prec | (sf & STRFMT_F_ALT)) != 0); | |
| 325 if (!p) p = lj_buf_more(sb, width > len ? width : len); | |
| 326 if (!(sf & (STRFMT_F_LEFT | STRFMT_F_ZERO))) { | |
| 327 while (width-- > len) *p++ = ' '; | |
| 328 } | |
| 329 if (prefix) *p++ = prefix; | |
| 330 *p++ = '0'; | |
| 331 *p++ = hexdig[17]; /* x or X */ | |
| 332 if ((sf & (STRFMT_F_LEFT | STRFMT_F_ZERO)) == STRFMT_F_ZERO) { | |
| 333 while (width-- > len) *p++ = '0'; | |
| 334 } | |
| 335 *p++ = '0' + (t.u32.hi >> 20); /* Usually '1', sometimes '0' or '2'. */ | |
| 336 if ((prec | (sf & STRFMT_F_ALT))) { | |
| 337 /* Emit fractional part. */ | |
| 338 char *q = p + 1 + prec; | |
| 339 *p = '.'; | |
| 340 if (prec < 13) t.u64 >>= (52 - prec*4); | |
| 341 else while (prec > 13) p[prec--] = '0'; | |
| 342 while (prec) { p[prec--] = hexdig[t.u64 & 15]; t.u64 >>= 4; } | |
| 343 p = q; | |
| 344 } | |
| 345 *p++ = hexdig[16]; /* p or P */ | |
| 346 *p++ = eprefix; /* + or - */ | |
| 347 p = lj_strfmt_wint(p, e); | |
| 348 } else { | |
| 349 /* %e or %f or %g - begin by converting n to "nd" format. */ | |
| 350 uint32_t nd[64]; | |
| 351 uint32_t ndhi = 0, ndlo, i; | |
| 352 int32_t e = (t.u32.hi >> 20) & 0x7ff, ndebias = 0; | |
| 353 char prefix = 0, *q; | |
| 354 if (t.u32.hi & 0x80000000) prefix = '-'; | |
| 355 else if ((sf & STRFMT_F_PLUS)) prefix = '+'; | |
| 356 else if ((sf & STRFMT_F_SPACE)) prefix = ' '; | |
| 357 prec += ((int32_t)prec >> 31) & 7; /* Default precision is 6. */ | |
| 358 if (STRFMT_FP(sf) == STRFMT_FP(STRFMT_T_FP_G)) { | |
| 359 /* %g - decrement precision if non-zero (to make it like %e). */ | |
| 360 prec--; | |
| 361 prec ^= (uint32_t)((int32_t)prec >> 31); | |
| 362 } | |
| 363 if ((sf & STRFMT_T_FP_E) && prec < 14 && n != 0) { | |
| 364 /* Precision is sufficiently low that rescaling will probably work. */ | |
| 365 if ((ndebias = rescale_e[e >> 6])) { | |
| 366 t.n = n * rescale_n[e >> 6]; | |
| 367 if (LJ_UNLIKELY(!e)) t.n *= 1e10, ndebias -= 10; | |
| 368 t.u64 -= 2; /* Convert 2ulp below (later we convert 2ulp above). */ | |
| 369 nd[0] = 0x100000 | (t.u32.hi & 0xfffff); | |
| 370 e = ((t.u32.hi >> 20) & 0x7ff) - 1075 - (ND_MUL2K_MAX_SHIFT < 29); | |
| 371 goto load_t_lo; rescale_failed: | |
| 372 t.n = n; | |
| 373 e = (t.u32.hi >> 20) & 0x7ff; | |
| 374 ndebias = ndhi = 0; | |
| 375 } | |
| 376 } | |
| 377 nd[0] = t.u32.hi & 0xfffff; | |
| 378 if (e == 0) e++; else nd[0] |= 0x100000; | |
| 379 e -= 1043; | |
| 380 if (t.u32.lo) { | |
| 381 e -= 32 + (ND_MUL2K_MAX_SHIFT < 29); load_t_lo: | |
| 382 #if ND_MUL2K_MAX_SHIFT >= 29 | |
| 383 nd[0] = (nd[0] << 3) | (t.u32.lo >> 29); | |
| 384 ndhi = nd_mul2k(nd, ndhi, 29, t.u32.lo & 0x1fffffff, sf); | |
| 385 #elif ND_MUL2K_MAX_SHIFT >= 11 | |
| 386 ndhi = nd_mul2k(nd, ndhi, 11, t.u32.lo >> 21, sf); | |
| 387 ndhi = nd_mul2k(nd, ndhi, 11, (t.u32.lo >> 10) & 0x7ff, sf); | |
| 388 ndhi = nd_mul2k(nd, ndhi, 11, (t.u32.lo << 1) & 0x7ff, sf); | |
| 389 #else | |
| 390 #error "ND_MUL2K_MAX_SHIFT too small" | |
| 391 #endif | |
| 392 } | |
| 393 if (e >= 0) { | |
| 394 ndhi = nd_mul2k(nd, ndhi, (uint32_t)e, 0, sf); | |
| 395 ndlo = 0; | |
| 396 } else { | |
| 397 ndlo = nd_div2k(nd, ndhi, (uint32_t)-e, sf); | |
| 398 if (ndhi && !nd[ndhi]) ndhi--; | |
| 399 } | |
| 400 /* abs(n) == nd * 10^ndebias (for slightly loose interpretation of ==) */ | |
| 401 if ((sf & STRFMT_T_FP_E)) { | |
| 402 /* %e or %g - assume %e and start by calculating nd's exponent (nde). */ | |
| 403 char eprefix = '+'; | |
| 404 int32_t nde = -1; | |
| 405 MSize hilen; | |
| 406 if (ndlo && !nd[ndhi]) { | |
| 407 ndhi = 64; do {} while (!nd[--ndhi]); | |
| 408 nde -= 64 * 9; | |
| 409 } | |
| 410 hilen = ndigits_dec(nd[ndhi]); | |
| 411 nde += ndhi * 9 + hilen; | |
| 412 if (ndebias) { | |
| 413 /* | |
| 414 ** Rescaling was performed, but this introduced some error, and might | |
| 415 ** have pushed us across a rounding boundary. We check whether this | |
| 416 ** error affected the result by introducing even more error (2ulp in | |
| 417 ** either direction), and seeing whether a rounding boundary was | |
| 418 ** crossed. Having already converted the -2ulp case, we save off its | |
| 419 ** most significant digits, convert the +2ulp case, and compare them. | |
| 420 */ | |
| 421 int32_t eidx = e + 70 + (ND_MUL2K_MAX_SHIFT < 29) | |
| 422 + (t.u32.lo >= 0xfffffffe && !(~t.u32.hi << 12)); | |
| 423 const int8_t *m_e = four_ulp_m_e + eidx * 2; | |
| 424 lj_assertG_(G(sbufL(sb)), 0 <= eidx && eidx < 128, "bad eidx %d", eidx); | |
| 425 nd[33] = nd[ndhi]; | |
| 426 nd[32] = nd[(ndhi - 1) & 0x3f]; | |
| 427 nd[31] = nd[(ndhi - 2) & 0x3f]; | |
| 428 nd_add_m10e(nd, ndhi, (uint8_t)*m_e, m_e[1]); | |
| 429 if (LJ_UNLIKELY(!nd_similar(nd, ndhi, nd + 33, hilen, prec + 1))) { | |
| 430 goto rescale_failed; | |
| 431 } | |
| 432 } | |
| 433 if ((int32_t)(prec - nde) < (0x3f & -(int32_t)ndlo) * 9) { | |
| 434 /* Precision is sufficiently low as to maybe require rounding. */ | |
| 435 ndhi = nd_add_m10e(nd, ndhi, 5, nde - prec - 1); | |
| 436 nde += (hilen != ndigits_dec(nd[ndhi])); | |
| 437 } | |
| 438 nde += ndebias; | |
| 439 if ((sf & STRFMT_T_FP_F)) { | |
| 440 /* %g */ | |
| 441 if ((int32_t)prec >= nde && nde >= -4) { | |
| 442 if (nde < 0) ndhi = 0; | |
| 443 prec -= nde; | |
| 444 goto g_format_like_f; | |
| 445 } else if (!(sf & STRFMT_F_ALT) && prec && width > 5) { | |
| 446 /* Decrease precision in order to strip trailing zeroes. */ | |
| 447 char tail[9]; | |
| 448 uint32_t maxprec = hilen - 1 + ((ndhi - ndlo) & 0x3f) * 9; | |
| 449 if (prec >= maxprec) prec = maxprec; | |
| 450 else ndlo = (ndhi - (((int32_t)(prec - hilen) + 9) / 9)) & 0x3f; | |
| 451 i = prec - hilen - (((ndhi - ndlo) & 0x3f) * 9) + 10; | |
| 452 lj_strfmt_wuint9(tail, nd[ndlo]); | |
| 453 while (prec && tail[--i] == '0') { | |
| 454 prec--; | |
| 455 if (!i) { | |
| 456 if (ndlo == ndhi) { prec = 0; break; } | |
| 457 lj_strfmt_wuint9(tail, nd[++ndlo]); | |
| 458 i = 9; | |
| 459 } | |
| 460 } | |
| 461 } | |
| 462 } | |
| 463 if (nde < 0) { | |
| 464 /* Make nde non-negative. */ | |
| 465 eprefix = '-'; | |
| 466 nde = -nde; | |
| 467 } | |
| 468 len = 3 + prec + (prefix != 0) + ndigits_dec((uint32_t)nde) + (nde < 10) | |
| 469 + ((prec | (sf & STRFMT_F_ALT)) != 0); | |
| 470 if (!p) p = lj_buf_more(sb, (width > len ? width : len) + 5); | |
| 471 if (!(sf & (STRFMT_F_LEFT | STRFMT_F_ZERO))) { | |
| 472 while (width-- > len) *p++ = ' '; | |
| 473 } | |
| 474 if (prefix) *p++ = prefix; | |
| 475 if ((sf & (STRFMT_F_LEFT | STRFMT_F_ZERO)) == STRFMT_F_ZERO) { | |
| 476 while (width-- > len) *p++ = '0'; | |
| 477 } | |
| 478 q = lj_strfmt_wint(p + 1, nd[ndhi]); | |
| 479 p[0] = p[1]; /* Put leading digit in the correct place. */ | |
| 480 if ((prec | (sf & STRFMT_F_ALT))) { | |
| 481 /* Emit fractional part. */ | |
| 482 p[1] = '.'; p += 2; | |
| 483 prec -= (MSize)(q - p); p = q; /* Account for digits already emitted. */ | |
| 484 /* Then emit chunks of 9 digits (this may emit 8 digits too many). */ | |
| 485 for (i = ndhi; (int32_t)prec > 0 && i != ndlo; prec -= 9) { | |
| 486 i = (i - 1) & 0x3f; | |
| 487 p = lj_strfmt_wuint9(p, nd[i]); | |
| 488 } | |
| 489 if ((sf & STRFMT_T_FP_F) && !(sf & STRFMT_F_ALT)) { | |
| 490 /* %g (and not %#g) - strip trailing zeroes. */ | |
| 491 p += (int32_t)prec & ((int32_t)prec >> 31); | |
| 492 while (p[-1] == '0') p--; | |
| 493 if (p[-1] == '.') p--; | |
| 494 } else { | |
| 495 /* %e (or %#g) - emit trailing zeroes. */ | |
| 496 while ((int32_t)prec > 0) { *p++ = '0'; prec--; } | |
| 497 p += (int32_t)prec; | |
| 498 } | |
| 499 } else { | |
| 500 p++; | |
| 501 } | |
| 502 *p++ = (sf & STRFMT_F_UPPER) ? 'E' : 'e'; | |
| 503 *p++ = eprefix; /* + or - */ | |
| 504 if (nde < 10) *p++ = '0'; /* Always at least two digits of exponent. */ | |
| 505 p = lj_strfmt_wint(p, nde); | |
| 506 } else { | |
| 507 /* %f (or, shortly, %g in %f style) */ | |
| 508 if (prec < (MSize)(0x3f & -(int32_t)ndlo) * 9) { | |
| 509 /* Precision is sufficiently low as to maybe require rounding. */ | |
| 510 ndhi = nd_add_m10e(nd, ndhi, 5, 0 - prec - 1); | |
| 511 } | |
| 512 g_format_like_f: | |
| 513 if ((sf & STRFMT_T_FP_E) && !(sf & STRFMT_F_ALT) && prec && width) { | |
| 514 /* Decrease precision in order to strip trailing zeroes. */ | |
| 515 if (ndlo) { | |
| 516 /* nd has a fractional part; we need to look at its digits. */ | |
| 517 char tail[9]; | |
| 518 uint32_t maxprec = (64 - ndlo) * 9; | |
| 519 if (prec >= maxprec) prec = maxprec; | |
| 520 else ndlo = 64 - (prec + 8) / 9; | |
| 521 i = prec - ((63 - ndlo) * 9); | |
| 522 lj_strfmt_wuint9(tail, nd[ndlo]); | |
| 523 while (prec && tail[--i] == '0') { | |
| 524 prec--; | |
| 525 if (!i) { | |
| 526 if (ndlo == 63) { prec = 0; break; } | |
| 527 lj_strfmt_wuint9(tail, nd[++ndlo]); | |
| 528 i = 9; | |
| 529 } | |
| 530 } | |
| 531 } else { | |
| 532 /* nd has no fractional part, so precision goes straight to zero. */ | |
| 533 prec = 0; | |
| 534 } | |
| 535 } | |
| 536 len = ndhi * 9 + ndigits_dec(nd[ndhi]) + prec + (prefix != 0) | |
| 537 + ((prec | (sf & STRFMT_F_ALT)) != 0); | |
| 538 if (!p) p = lj_buf_more(sb, (width > len ? width : len) + 8); | |
| 539 if (!(sf & (STRFMT_F_LEFT | STRFMT_F_ZERO))) { | |
| 540 while (width-- > len) *p++ = ' '; | |
| 541 } | |
| 542 if (prefix) *p++ = prefix; | |
| 543 if ((sf & (STRFMT_F_LEFT | STRFMT_F_ZERO)) == STRFMT_F_ZERO) { | |
| 544 while (width-- > len) *p++ = '0'; | |
| 545 } | |
| 546 /* Emit integer part. */ | |
| 547 p = lj_strfmt_wint(p, nd[ndhi]); | |
| 548 i = ndhi; | |
| 549 while (i) p = lj_strfmt_wuint9(p, nd[--i]); | |
| 550 if ((prec | (sf & STRFMT_F_ALT))) { | |
| 551 /* Emit fractional part. */ | |
| 552 *p++ = '.'; | |
| 553 /* Emit chunks of 9 digits (this may emit 8 digits too many). */ | |
| 554 while ((int32_t)prec > 0 && i != ndlo) { | |
| 555 i = (i - 1) & 0x3f; | |
| 556 p = lj_strfmt_wuint9(p, nd[i]); | |
| 557 prec -= 9; | |
| 558 } | |
| 559 if ((sf & STRFMT_T_FP_E) && !(sf & STRFMT_F_ALT)) { | |
| 560 /* %g (and not %#g) - strip trailing zeroes. */ | |
| 561 p += (int32_t)prec & ((int32_t)prec >> 31); | |
| 562 while (p[-1] == '0') p--; | |
| 563 if (p[-1] == '.') p--; | |
| 564 } else { | |
| 565 /* %f (or %#g) - emit trailing zeroes. */ | |
| 566 while ((int32_t)prec > 0) { *p++ = '0'; prec--; } | |
| 567 p += (int32_t)prec; | |
| 568 } | |
| 569 } | |
| 570 } | |
| 571 } | |
| 572 if ((sf & STRFMT_F_LEFT)) while (width-- > len) *p++ = ' '; | |
| 573 return p; | |
| 574 } | |
| 575 | |
| 576 /* Add formatted floating-point number to buffer. */ | |
| 577 SBuf *lj_strfmt_putfnum(SBuf *sb, SFormat sf, lua_Number n) | |
| 578 { | |
| 579 sb->w = lj_strfmt_wfnum(sb, sf, n, NULL); | |
| 580 return sb; | |
| 581 } | |
| 582 | |
| 583 /* -- Conversions to strings ---------------------------------------------- */ | |
| 584 | |
| 585 /* Convert number to string. */ | |
| 586 GCstr * LJ_FASTCALL lj_strfmt_num(lua_State *L, cTValue *o) | |
| 587 { | |
| 588 char buf[STRFMT_MAXBUF_NUM]; | |
| 589 MSize len = (MSize)(lj_strfmt_wfnum(NULL, STRFMT_G14, o->n, buf) - buf); | |
| 590 return lj_str_new(L, buf, len); | |
| 591 } | |
| 592 |