Commit 8fc48e8b authored by Piotr Caban's avatar Piotr Caban Committed by Alexandre Julliard

msvcrt: Create 64-bit mantissa in fpnum_parse.

parent 45001578
......@@ -28,7 +28,8 @@ static const int p10s[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000,
#define LIMB_MAX 1000000000 /* 10^9 */
#define BNUM_PREC64 128 /* data size needed to store 64-bit double */
/* bnum represents real number with fixed decimal point (after 2 limbs) */
/* bnum represents real number with fixed decimal point */
struct bnum {
int b; /* least significant digit position */
int e; /* most significant digit position + 1 */
......@@ -41,14 +42,6 @@ static inline int bnum_idx(struct bnum *b, int idx)
return idx & (b->size - 1);
}
/* Returns integral part of bnum */
static inline ULONGLONG bnum_to_mant(struct bnum *b)
{
ULONGLONG ret = (ULONGLONG)b->data[bnum_idx(b, b->e-1)] * LIMB_MAX;
if(b->b != b->e-1) ret += b->data[bnum_idx(b, b->e-2)];
return ret;
}
/* Returns TRUE if new most significant limb was added */
static inline BOOL bnum_lshift(struct bnum *b, int shift)
{
......
......@@ -597,6 +597,21 @@ static struct fpnum fpnum_parse16(MSVCRT_wchar_t get(void *ctx), void unget(void
}
#endif
/* Converts first 3 limbs to ULONGLONG */
/* Return FALSE on overflow */
static inline BOOL bnum_to_mant(struct bnum *b, ULONGLONG *m)
{
if(MSVCRT_UI64_MAX / LIMB_MAX / LIMB_MAX < b->data[bnum_idx(b, b->e-1)]) return FALSE;
*m = (ULONGLONG)b->data[bnum_idx(b, b->e-1)] * LIMB_MAX * LIMB_MAX;
if(b->b == b->e-1) return TRUE;
if(MSVCRT_UI64_MAX - *m < (ULONGLONG)b->data[bnum_idx(b, b->e-2)] * LIMB_MAX) return FALSE;
*m += (ULONGLONG)b->data[bnum_idx(b, b->e-2)] * LIMB_MAX;
if(b->b == b->e-2) return TRUE;
if(MSVCRT_UI64_MAX - *m < b->data[bnum_idx(b, b->e-3)]) return FALSE;
*m += b->data[bnum_idx(b, b->e-3)];
return TRUE;
}
struct fpnum fpnum_parse(MSVCRT_wchar_t (*get)(void *ctx), void (*unget)(void *ctx),
void *ctx, MSVCRT_pthreadlocinfo locinfo)
{
......@@ -612,6 +627,7 @@ struct fpnum fpnum_parse(MSVCRT_wchar_t (*get)(void *ctx), void (*unget)(void *c
struct bnum *b = (struct bnum*)bnum_data;
enum fpmod round = FP_ROUND_ZERO;
MSVCRT_wchar_t nch;
ULONGLONG m;
nch = get(ctx);
if(nch == '-') {
......@@ -797,28 +813,33 @@ struct fpnum fpnum_parse(MSVCRT_wchar_t (*get)(void *ctx), void (*unget)(void *c
if(dp-1 < MSVCRT_DBL_MIN_10_EXP-MSVCRT_DBL_DIG-18)
return fpnum(sign, INT_MIN, 1, FP_ROUND_ZERO);
while(dp > 2*LIMB_DIGITS) {
while(dp > 3*LIMB_DIGITS) {
if(bnum_rshift(b, 9)) dp -= LIMB_DIGITS;
e2 += 9;
}
while(dp <= LIMB_DIGITS) {
while(dp <= 2*LIMB_DIGITS) {
if(bnum_lshift(b, 29)) dp += LIMB_DIGITS;
e2 -= 29;
}
while(b->data[bnum_idx(b, b->e-1)] < LIMB_MAX/10) {
/* Make sure most significant mantissa bit will be set */
while(b->data[bnum_idx(b, b->e-1)] <= 9) {
bnum_lshift(b, 1);
e2--;
}
while(!bnum_to_mant(b, &m)) {
bnum_rshift(b, 1);
e2++;
}
/* Check if fractional part is non-zero */
/* Caution: it's only correct because bnum_to_mant returns more than 53 bits */
for(i=b->e-3; i>=b->b; i--) {
for(i=b->e-4; i>=b->b; i--) {
if (!b->data[bnum_idx(b, b->b)]) continue;
round = FP_ROUND_DOWN;
break;
}
return fpnum(sign, e2, bnum_to_mant(b), round);
return fpnum(sign, e2, m, round);
}
static MSVCRT_wchar_t strtod_str_get(void *ctx)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment