diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/lj_strfmt_num.c | 43 |
1 files changed, 40 insertions, 3 deletions
diff --git a/src/lj_strfmt_num.c b/src/lj_strfmt_num.c index a33fc63a..35ff1bc9 100644 --- a/src/lj_strfmt_num.c +++ b/src/lj_strfmt_num.c | |||
| @@ -169,7 +169,9 @@ static uint32_t nd_div2k(uint32_t* nd, uint32_t ndhi, uint32_t k, SFormat sf) | |||
| 169 | } | 169 | } |
| 170 | if (k > 18) { | 170 | if (k > 18) { |
| 171 | if (STRFMT_FP(sf) == STRFMT_FP(STRFMT_T_FP_F)) { | 171 | if (STRFMT_FP(sf) == STRFMT_FP(STRFMT_T_FP_F)) { |
| 172 | stop1 = 63 - (int32_t)STRFMT_PREC(sf) / 9; | 172 | /* Must not limit precision here or nd_round cannot round to even. |
| 173 | ** stop1 = 63 - (int32_t)STRFMT_PREC(sf) / 9; | ||
| 174 | */ | ||
| 173 | } else { | 175 | } else { |
| 174 | int32_t floorlog2 = ndhi * 29 + lj_fls(nd[ndhi]) - k; | 176 | int32_t floorlog2 = ndhi * 29 + lj_fls(nd[ndhi]) - k; |
| 175 | int32_t floorlog10 = (int32_t)(floorlog2 * 0.30102999566398114); | 177 | int32_t floorlog10 = (int32_t)(floorlog2 * 0.30102999566398114); |
| @@ -242,6 +244,41 @@ static uint32_t nd_add_m10e(uint32_t* nd, uint32_t ndhi, uint8_t m, int32_t e) | |||
| 242 | return ndhi; | 244 | return ndhi; |
| 243 | } | 245 | } |
| 244 | 246 | ||
| 247 | /* Round to even with given precision. Extra digits are not zeroed. */ | ||
| 248 | static uint32_t nd_round(uint32_t* nd, uint32_t ndlo, uint32_t ndhi, int32_t e) | ||
| 249 | { | ||
| 250 | uint32_t i; | ||
| 251 | int32_t d; | ||
| 252 | char buf[9]; | ||
| 253 | if (e >= 0) { | ||
| 254 | i = (uint32_t)e / 9; | ||
| 255 | d = 8 - e + (int32_t)i * 9; | ||
| 256 | } else { | ||
| 257 | int32_t f = (e - 8) / 9; | ||
| 258 | i = (uint32_t)(64 + f); | ||
| 259 | d = 8 - e + f * 9; | ||
| 260 | } | ||
| 261 | lj_strfmt_wuint9(buf, nd[i]); | ||
| 262 | if (buf[d] < '5') { | ||
| 263 | return ndhi; /* Don't round up. */ | ||
| 264 | } else if (buf[d] == '5') { /* Must check for round to even. */ | ||
| 265 | if (d ? (buf[d-1] & 1) : (nd[(i + 1) & 0x3f] & 1)) | ||
| 266 | goto round_up; /* Round up '[13579]5.*' */ | ||
| 267 | while (++d < 9) { /* Check remaining digits in buffer. */ | ||
| 268 | if (buf[d] != '0') | ||
| 269 | goto round_up; /* Round up '[02468]5[^0]*'. */ | ||
| 270 | } | ||
| 271 | while (i != ndlo) { /* Check remaining fraction. */ | ||
| 272 | if (nd[i]) | ||
| 273 | goto round_up; /* Round up '[02468]5[^0]*'. */ | ||
| 274 | i = (i - 1) & 0x3f; | ||
| 275 | } | ||
| 276 | return ndhi; /* Don't round up. */ | ||
| 277 | } /* else: round up.*/ | ||
| 278 | round_up: | ||
| 279 | return nd_add_m10e(nd, ndhi, 5, e); /* Round up by adding 5*10^e. */ | ||
| 280 | } | ||
| 281 | |||
| 245 | /* Test whether two "nd" values are equal in their most significant digits. */ | 282 | /* 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, | 283 | static int nd_similar(uint32_t* nd, uint32_t ndhi, uint32_t* ref, MSize hilen, |
| 247 | MSize prec) | 284 | MSize prec) |
| @@ -432,7 +469,7 @@ static char *lj_strfmt_wfnum(SBuf *sb, SFormat sf, lua_Number n, char *p) | |||
| 432 | } | 469 | } |
| 433 | if ((int32_t)(prec - nde) < (0x3f & -(int32_t)ndlo) * 9) { | 470 | if ((int32_t)(prec - nde) < (0x3f & -(int32_t)ndlo) * 9) { |
| 434 | /* Precision is sufficiently low as to maybe require rounding. */ | 471 | /* Precision is sufficiently low as to maybe require rounding. */ |
| 435 | ndhi = nd_add_m10e(nd, ndhi, 5, nde - prec - 1); | 472 | ndhi = nd_round(nd, ndlo, ndhi, nde - prec - 1); |
| 436 | nde += (hilen != ndigits_dec(nd[ndhi])); | 473 | nde += (hilen != ndigits_dec(nd[ndhi])); |
| 437 | } | 474 | } |
| 438 | nde += ndebias; | 475 | nde += ndebias; |
| @@ -508,7 +545,7 @@ static char *lj_strfmt_wfnum(SBuf *sb, SFormat sf, lua_Number n, char *p) | |||
| 508 | /* %f (or, shortly, %g in %f style) */ | 545 | /* %f (or, shortly, %g in %f style) */ |
| 509 | if (prec < (MSize)(0x3f & -(int32_t)ndlo) * 9) { | 546 | if (prec < (MSize)(0x3f & -(int32_t)ndlo) * 9) { |
| 510 | /* Precision is sufficiently low as to maybe require rounding. */ | 547 | /* Precision is sufficiently low as to maybe require rounding. */ |
| 511 | ndhi = nd_add_m10e(nd, ndhi, 5, 0 - prec - 1); | 548 | ndhi = nd_round(nd, ndlo, ndhi, 0 - prec - 1); |
| 512 | } | 549 | } |
| 513 | g_format_like_f: | 550 | g_format_like_f: |
| 514 | if ((sf & STRFMT_T_FP_E) && !(sf & STRFMT_F_ALT) && prec && width) { | 551 | if ((sf & STRFMT_T_FP_E) && !(sf & STRFMT_F_ALT) && prec && width) { |
