#include <math.h>
#include <float.h>
#include <limits.h>
+#include <errno.h>
#include "shgetc.h"
#include "floatscan.h"
}
for (x=0; c-'0'<10U && x<INT_MAX/10; c = shgetc(f))
x = 10*x + c-'0';
- for (y=x; c-'0'<10U && x<LLONG_MAX/10; c = shgetc(f))
+ for (y=x; c-'0'<10U && x<LLONG_MAX/100; c = shgetc(f))
y = 10*y + c-'0';
for (; c-'0'<10U; c = shgetc(f));
shunget(f);
}
-static long double decfloat(FILE *f, int bits, int emin, int sign, int pok)
+static long double decfloat(FILE *f, int c, int bits, int emin, int sign, int pok)
{
uint32_t x[KMAX];
static const uint32_t th[] = { LD_B1B_MAX };
long double y;
long double frac=0;
long double bias=0;
- int c;
j=0;
k=0;
- c = shgetc(f);
-
/* Don't let leading zeros consume buffer space */
for (; c=='0'; c = shgetc(f)) gotdig=1;
shunget(f);
}
if (!gotdig) {
+ errno = EINVAL;
shlim(f, 0);
return 0;
}
return sign * 0.0;
if (lrp==dc && (!k || (k==1 && !j)) && (bits>30 || x[0]>>bits==0))
return sign * (long double)x[0];
- if (lrp > -emin/2)
+ if (lrp > -emin/2) {
+ errno = ERANGE;
return sign * LDBL_MAX * LDBL_MAX;
- if (lrp < emin-2*LDBL_MANT_DIG)
+ }
+ if (lrp < emin-2*LDBL_MANT_DIG) {
+ errno = ERANGE;
return sign * LDBL_MIN * LDBL_MIN;
+ }
if (k<KMAX && j) {
for (; j<9; j++) x[k]*=10;
e2 = 0;
rp = lrp;
- while (rp < 18+9*LD_B1B_DIG) {
- uint32_t carry = 0;
- e2 -= 29;
- for (k=(z-1 & MASK); ; k=(k-1 & MASK)) {
- uint64_t tmp = ((uint64_t)x[k] << 29) + carry;
- if (tmp > 1000000000) {
- carry = tmp / 1000000000;
- x[k] = tmp % 1000000000;
- } else {
- carry = 0;
- x[k] = tmp;
- }
- if (k==(z-1 & MASK) && k!=a && !x[k]) z = k;
- if (k==a) break;
- }
- if (carry) {
- rp += 9;
- if (a == z) {
- z = (z-1 & MASK);
- x[z-1 & MASK] |= x[z];
- }
- a = (a-1 & MASK);
- x[a] = carry;
- }
- }
-
if (rp % 9) {
static const int p10s[] = {
100000000, 10000000, 1000000, 100000,
10000, 1000, 100, 10
};
- int rpm9 = rp % 9;
+ int rpm9 = rp>=0 ? rp%9 : rp%9+9;
int p10 = p10s[rpm9-1];
uint32_t carry = 0;
for (k=a; k!=z; k=(k+1 & MASK)) {
rp += 9-rpm9;
}
+ while (rp < 9*LD_B1B_DIG || (rp == 9*LD_B1B_DIG && x[0]<th[0])) {
+ uint32_t carry = 0;
+ e2 -= 29;
+ for (k=(z-1 & MASK); ; k=(k-1 & MASK)) {
+ uint64_t tmp = ((uint64_t)x[k] << 29) + carry;
+ if (tmp > 1000000000) {
+ carry = tmp / 1000000000;
+ x[k] = tmp % 1000000000;
+ } else {
+ carry = 0;
+ x[k] = tmp;
+ }
+ if (k==(z-1 & MASK) && k!=a && !x[k]) z = k;
+ if (k==a) break;
+ }
+ if (carry) {
+ rp += 9;
+ if (a == z) {
+ z = (z-1 & MASK);
+ x[z-1 & MASK] |= x[z];
+ }
+ a = (a-1 & MASK);
+ x[a] = carry;
+ }
+ }
+
for (;;) {
uint32_t carry = 0;
int sh = 1;
}
}
- for (y=i=0; i<LD_B1B_DIG && (a+i & MASK)!=z; i++)
+ for (y=i=0; i<LD_B1B_DIG; i++) {
+ if ((a+i & MASK)==z) x[z=(z+1 & MASK)] = 0;
y = 1000000000.0L * y + x[a+i & MASK];
+ }
y *= sign;
y = scalbnl(y, e2);
+ if (!y) errno = ERANGE;
+
return y;
}
}
e2 = 0;
}
+ } else {
+ shunget(f);
}
e2 += 4*rp - 32;
if (!x) return sign * 0.0;
- if (e2 > -emin) return sign * LDBL_MAX * LDBL_MAX;
- if (e2 < emin-2*LDBL_MANT_DIG) return sign * LDBL_MIN * LDBL_MIN;
+ if (e2 > -emin) {
+ errno = ERANGE;
+ return sign * LDBL_MAX * LDBL_MAX;
+ }
+ if (e2 < emin-2*LDBL_MANT_DIG) {
+ errno = ERANGE;
+ return sign * LDBL_MIN * LDBL_MIN;
+ }
while (x < 0x80000000) {
if (y>=0.5) {
y = bias + sign*(long double)x + sign*y;
y -= bias;
+ if (!y) errno = ERANGE;
+
return scalbnl(y, e2);
}
if (i) {
shunget(f);
+ errno = EINVAL;
shlim(f, 0);
return 0;
}
c = shgetc(f);
if ((c|32) == 'x')
return hexfloat(f, bits, emin, sign, pok);
+ shunget(f);
c = '0';
}
- shunget(f);
- return decfloat(f, bits, emin, sign, pok);
+ return decfloat(f, c, bits, emin, sign, pok);
}