floatscan.c raw

   1  #include <stdint.h>
   2  #include <stdio.h>
   3  #include <math.h>
   4  #include <float.h>
   5  #include <limits.h>
   6  #include <errno.h>
   7  #include <ctype.h>
   8  
   9  #include "shgetc.h"
  10  #include "floatscan.h"
  11  
  12  #if LDBL_MANT_DIG == 53 && LDBL_MAX_EXP == 1024
  13  
  14  #define LD_B1B_DIG 2
  15  #define LD_B1B_MAX 9007199, 254740991
  16  #define KMAX 128
  17  
  18  #elif LDBL_MANT_DIG == 64 && LDBL_MAX_EXP == 16384
  19  
  20  #define LD_B1B_DIG 3
  21  #define LD_B1B_MAX 18, 446744073, 709551615
  22  #define KMAX 2048
  23  
  24  #elif LDBL_MANT_DIG == 113 && LDBL_MAX_EXP == 16384
  25  
  26  #define LD_B1B_DIG 4
  27  #define LD_B1B_MAX 10384593, 717069655, 257060992, 658440191
  28  #define KMAX 2048
  29  
  30  #else
  31  #error Unsupported long double representation
  32  #endif
  33  
  34  #define MASK (KMAX-1)
  35  
  36  static long long scanexp(FILE *f, int pok)
  37  {
  38  	int c;
  39  	int x;
  40  	long long y;
  41  	int neg = 0;
  42  	
  43  	c = shgetc(f);
  44  	if (c=='+' || c=='-') {
  45  		neg = (c=='-');
  46  		c = shgetc(f);
  47  		if (c-'0'>=10U && pok) shunget(f);
  48  	}
  49  	if (c-'0'>=10U) {
  50  		shunget(f);
  51  		return LLONG_MIN;
  52  	}
  53  	for (x=0; c-'0'<10U && x<INT_MAX/10; c = shgetc(f))
  54  		x = 10*x + c-'0';
  55  	for (y=x; c-'0'<10U && y<LLONG_MAX/100; c = shgetc(f))
  56  		y = 10*y + c-'0';
  57  	for (; c-'0'<10U; c = shgetc(f));
  58  	shunget(f);
  59  	return neg ? -y : y;
  60  }
  61  
  62  
  63  static long double decfloat(FILE *f, int c, int bits, int emin, int sign, int pok)
  64  {
  65  	uint32_t x[KMAX];
  66  	static const uint32_t th[] = { LD_B1B_MAX };
  67  	int i, j, k, a, z;
  68  	long long lrp=0, dc=0;
  69  	long long e10=0;
  70  	int lnz = 0;
  71  	int gotdig = 0, gotrad = 0;
  72  	int rp;
  73  	int e2;
  74  	int emax = -emin-bits+3;
  75  	int denormal = 0;
  76  	long double y;
  77  	long double frac=0;
  78  	long double bias=0;
  79  	static const int p10s[] = { 10, 100, 1000, 10000,
  80  		100000, 1000000, 10000000, 100000000 };
  81  
  82  	j=0;
  83  	k=0;
  84  
  85  	/* Don't let leading zeros consume buffer space */
  86  	for (; c=='0'; c = shgetc(f)) gotdig=1;
  87  	if (c=='.') {
  88  		gotrad = 1;
  89  		for (c = shgetc(f); c=='0'; c = shgetc(f)) gotdig=1, lrp--;
  90  	}
  91  
  92  	x[0] = 0;
  93  	for (; c-'0'<10U || c=='.'; c = shgetc(f)) {
  94  		if (c == '.') {
  95  			if (gotrad) break;
  96  			gotrad = 1;
  97  			lrp = dc;
  98  		} else if (k < KMAX-3) {
  99  			dc++;
 100  			if (c!='0') lnz = dc;
 101  			if (j) x[k] = x[k]*10 + c-'0';
 102  			else x[k] = c-'0';
 103  			if (++j==9) {
 104  				k++;
 105  				j=0;
 106  			}
 107  			gotdig=1;
 108  		} else {
 109  			dc++;
 110  			if (c!='0') {
 111  				lnz = (KMAX-4)*9;
 112  				x[KMAX-4] |= 1;
 113  			}
 114  		}
 115  	}
 116  	if (!gotrad) lrp=dc;
 117  
 118  	if (gotdig && (c|32)=='e') {
 119  		e10 = scanexp(f, pok);
 120  		if (e10 == LLONG_MIN) {
 121  			if (pok) {
 122  				shunget(f);
 123  			} else {
 124  				shlim(f, 0);
 125  				return 0;
 126  			}
 127  			e10 = 0;
 128  		}
 129  		lrp += e10;
 130  	} else if (c>=0) {
 131  		shunget(f);
 132  	}
 133  	if (!gotdig) {
 134  		errno = EINVAL;
 135  		shlim(f, 0);
 136  		return 0;
 137  	}
 138  
 139  	/* Handle zero specially to avoid nasty special cases later */
 140  	if (!x[0]) return sign * 0.0;
 141  
 142  	/* Optimize small integers (w/no exponent) and over/under-flow */
 143  	if (lrp==dc && dc<10 && (bits>30 || x[0]>>bits==0))
 144  		return sign * (long double)x[0];
 145  	if (lrp > -emin/2) {
 146  		errno = ERANGE;
 147  		return sign * LDBL_MAX * LDBL_MAX;
 148  	}
 149  	if (lrp < emin-2*LDBL_MANT_DIG) {
 150  		errno = ERANGE;
 151  		return sign * LDBL_MIN * LDBL_MIN;
 152  	}
 153  
 154  	/* Align incomplete final B1B digit */
 155  	if (j) {
 156  		for (; j<9; j++) x[k]*=10;
 157  		k++;
 158  		j=0;
 159  	}
 160  
 161  	a = 0;
 162  	z = k;
 163  	e2 = 0;
 164  	rp = lrp;
 165  
 166  	/* Optimize small to mid-size integers (even in exp. notation) */
 167  	if (lnz<9 && lnz<=rp && rp < 18) {
 168  		if (rp == 9) return sign * (long double)x[0];
 169  		if (rp < 9) return sign * (long double)x[0] / p10s[8-rp];
 170  		int bitlim = bits-3*(int)(rp-9);
 171  		if (bitlim>30 || x[0]>>bitlim==0)
 172  			return sign * (long double)x[0] * p10s[rp-10];
 173  	}
 174  
 175  	/* Drop trailing zeros */
 176  	for (; !x[z-1]; z--);
 177  
 178  	/* Align radix point to B1B digit boundary */
 179  	if (rp % 9) {
 180  		int rpm9 = rp>=0 ? rp%9 : rp%9+9;
 181  		int p10 = p10s[8-rpm9];
 182  		uint32_t carry = 0;
 183  		for (k=a; k!=z; k++) {
 184  			uint32_t tmp = x[k] % p10;
 185  			x[k] = x[k]/p10 + carry;
 186  			carry = 1000000000/p10 * tmp;
 187  			if (k==a && !x[k]) {
 188  				a = (a+1 & MASK);
 189  				rp -= 9;
 190  			}
 191  		}
 192  		if (carry) x[z++] = carry;
 193  		rp += 9-rpm9;
 194  	}
 195  
 196  	/* Upscale until desired number of bits are left of radix point */
 197  	while (rp < 9*LD_B1B_DIG || (rp == 9*LD_B1B_DIG && x[a]<th[0])) {
 198  		uint32_t carry = 0;
 199  		e2 -= 29;
 200  		for (k=(z-1 & MASK); ; k=(k-1 & MASK)) {
 201  			uint64_t tmp = ((uint64_t)x[k] << 29) + carry;
 202  			if (tmp > 1000000000) {
 203  				carry = tmp / 1000000000;
 204  				x[k] = tmp % 1000000000;
 205  			} else {
 206  				carry = 0;
 207  				x[k] = tmp;
 208  			}
 209  			if (k==(z-1 & MASK) && k!=a && !x[k]) z = k;
 210  			if (k==a) break;
 211  		}
 212  		if (carry) {
 213  			rp += 9;
 214  			a = (a-1 & MASK);
 215  			if (a == z) {
 216  				z = (z-1 & MASK);
 217  				x[z-1 & MASK] |= x[z];
 218  			}
 219  			x[a] = carry;
 220  		}
 221  	}
 222  
 223  	/* Downscale until exactly number of bits are left of radix point */
 224  	for (;;) {
 225  		uint32_t carry = 0;
 226  		int sh = 1;
 227  		for (i=0; i<LD_B1B_DIG; i++) {
 228  			k = (a+i & MASK);
 229  			if (k == z || x[k] < th[i]) {
 230  				i=LD_B1B_DIG;
 231  				break;
 232  			}
 233  			if (x[a+i & MASK] > th[i]) break;
 234  		}
 235  		if (i==LD_B1B_DIG && rp==9*LD_B1B_DIG) break;
 236  		/* FIXME: find a way to compute optimal sh */
 237  		if (rp > 9+9*LD_B1B_DIG) sh = 9;
 238  		e2 += sh;
 239  		for (k=a; k!=z; k=(k+1 & MASK)) {
 240  			uint32_t tmp = x[k] & (1<<sh)-1;
 241  			x[k] = (x[k]>>sh) + carry;
 242  			carry = (1000000000>>sh) * tmp;
 243  			if (k==a && !x[k]) {
 244  				a = (a+1 & MASK);
 245  				i--;
 246  				rp -= 9;
 247  			}
 248  		}
 249  		if (carry) {
 250  			if ((z+1 & MASK) != a) {
 251  				x[z] = carry;
 252  				z = (z+1 & MASK);
 253  			} else x[z-1 & MASK] |= 1;
 254  		}
 255  	}
 256  
 257  	/* Assemble desired bits into floating point variable */
 258  	for (y=i=0; i<LD_B1B_DIG; i++) {
 259  		if ((a+i & MASK)==z) x[(z=(z+1 & MASK))-1] = 0;
 260  		y = 1000000000.0L * y + x[a+i & MASK];
 261  	}
 262  
 263  	y *= sign;
 264  
 265  	/* Limit precision for denormal results */
 266  	if (bits > LDBL_MANT_DIG+e2-emin) {
 267  		bits = LDBL_MANT_DIG+e2-emin;
 268  		if (bits<0) bits=0;
 269  		denormal = 1;
 270  	}
 271  
 272  	/* Calculate bias term to force rounding, move out lower bits */
 273  	if (bits < LDBL_MANT_DIG) {
 274  		bias = copysignl(scalbn(1, 2*LDBL_MANT_DIG-bits-1), y);
 275  		frac = fmodl(y, scalbn(1, LDBL_MANT_DIG-bits));
 276  		y -= frac;
 277  		y += bias;
 278  	}
 279  
 280  	/* Process tail of decimal input so it can affect rounding */
 281  	if ((a+i & MASK) != z) {
 282  		uint32_t t = x[a+i & MASK];
 283  		if (t < 500000000 && (t || (a+i+1 & MASK) != z))
 284  			frac += 0.25*sign;
 285  		else if (t > 500000000)
 286  			frac += 0.75*sign;
 287  		else if (t == 500000000) {
 288  			if ((a+i+1 & MASK) == z)
 289  				frac += 0.5*sign;
 290  			else
 291  				frac += 0.75*sign;
 292  		}
 293  		if (LDBL_MANT_DIG-bits >= 2 && !fmodl(frac, 1))
 294  			frac++;
 295  	}
 296  
 297  	y += frac;
 298  	y -= bias;
 299  
 300  	if ((e2+LDBL_MANT_DIG & INT_MAX) > emax-5) {
 301  		if (fabsl(y) >= 2/LDBL_EPSILON) {
 302  			if (denormal && bits==LDBL_MANT_DIG+e2-emin)
 303  				denormal = 0;
 304  			y *= 0.5;
 305  			e2++;
 306  		}
 307  		if (e2+LDBL_MANT_DIG>emax || (denormal && frac))
 308  			errno = ERANGE;
 309  	}
 310  
 311  	return scalbnl(y, e2);
 312  }
 313  
 314  static long double hexfloat(FILE *f, int bits, int emin, int sign, int pok)
 315  {
 316  	uint32_t x = 0;
 317  	long double y = 0;
 318  	long double scale = 1;
 319  	long double bias = 0;
 320  	int gottail = 0, gotrad = 0, gotdig = 0;
 321  	long long rp = 0;
 322  	long long dc = 0;
 323  	long long e2 = 0;
 324  	int d;
 325  	int c;
 326  
 327  	c = shgetc(f);
 328  
 329  	/* Skip leading zeros */
 330  	for (; c=='0'; c = shgetc(f)) gotdig = 1;
 331  
 332  	if (c=='.') {
 333  		gotrad = 1;
 334  		c = shgetc(f);
 335  		/* Count zeros after the radix point before significand */
 336  		for (rp=0; c=='0'; c = shgetc(f), rp--) gotdig = 1;
 337  	}
 338  
 339  	for (; c-'0'<10U || (c|32)-'a'<6U || c=='.'; c = shgetc(f)) {
 340  		if (c=='.') {
 341  			if (gotrad) break;
 342  			rp = dc;
 343  			gotrad = 1;
 344  		} else {
 345  			gotdig = 1;
 346  			if (c > '9') d = (c|32)+10-'a';
 347  			else d = c-'0';
 348  			if (dc<8) {
 349  				x = x*16 + d;
 350  			} else if (dc < LDBL_MANT_DIG/4+1) {
 351  				y += d*(scale/=16);
 352  			} else if (d && !gottail) {
 353  				y += 0.5*scale;
 354  				gottail = 1;
 355  			}
 356  			dc++;
 357  		}
 358  	}
 359  	if (!gotdig) {
 360  		shunget(f);
 361  		if (pok) {
 362  			shunget(f);
 363  			if (gotrad) shunget(f);
 364  		} else {
 365  			shlim(f, 0);
 366  		}
 367  		return sign * 0.0;
 368  	}
 369  	if (!gotrad) rp = dc;
 370  	while (dc<8) x *= 16, dc++;
 371  	if ((c|32)=='p') {
 372  		e2 = scanexp(f, pok);
 373  		if (e2 == LLONG_MIN) {
 374  			if (pok) {
 375  				shunget(f);
 376  			} else {
 377  				shlim(f, 0);
 378  				return 0;
 379  			}
 380  			e2 = 0;
 381  		}
 382  	} else {
 383  		shunget(f);
 384  	}
 385  	e2 += 4*rp - 32;
 386  
 387  	if (!x) return sign * 0.0;
 388  	if (e2 > -emin) {
 389  		errno = ERANGE;
 390  		return sign * LDBL_MAX * LDBL_MAX;
 391  	}
 392  	if (e2 < emin-2*LDBL_MANT_DIG) {
 393  		errno = ERANGE;
 394  		return sign * LDBL_MIN * LDBL_MIN;
 395  	}
 396  
 397  	while (x < 0x80000000) {
 398  		if (y>=0.5) {
 399  			x += x + 1;
 400  			y += y - 1;
 401  		} else {
 402  			x += x;
 403  			y += y;
 404  		}
 405  		e2--;
 406  	}
 407  
 408  	if (bits > 32+e2-emin) {
 409  		bits = 32+e2-emin;
 410  		if (bits<0) bits=0;
 411  	}
 412  
 413  	if (bits < LDBL_MANT_DIG)
 414  		bias = copysignl(scalbn(1, 32+LDBL_MANT_DIG-bits-1), sign);
 415  
 416  	if (bits<32 && y && !(x&1)) x++, y=0;
 417  
 418  	y = bias + sign*(long double)x + sign*y;
 419  	y -= bias;
 420  
 421  	if (!y) errno = ERANGE;
 422  
 423  	return scalbnl(y, e2);
 424  }
 425  
 426  long double __floatscan(FILE *f, int prec, int pok)
 427  {
 428  	int sign = 1;
 429  	size_t i;
 430  	int bits;
 431  	int emin;
 432  	int c;
 433  
 434  	switch (prec) {
 435  	case 0:
 436  		bits = FLT_MANT_DIG;
 437  		emin = FLT_MIN_EXP-bits;
 438  		break;
 439  	case 1:
 440  		bits = DBL_MANT_DIG;
 441  		emin = DBL_MIN_EXP-bits;
 442  		break;
 443  	case 2:
 444  		bits = LDBL_MANT_DIG;
 445  		emin = LDBL_MIN_EXP-bits;
 446  		break;
 447  	default:
 448  		return 0;
 449  	}
 450  
 451  	while (isspace((c=shgetc(f))));
 452  
 453  	if (c=='+' || c=='-') {
 454  		sign -= 2*(c=='-');
 455  		c = shgetc(f);
 456  	}
 457  
 458  	for (i=0; i<8 && (c|32)=="infinity"[i]; i++)
 459  		if (i<7) c = shgetc(f);
 460  	if (i==3 || i==8 || (i>3 && pok)) {
 461  		if (i!=8) {
 462  			shunget(f);
 463  			if (pok) for (; i>3; i--) shunget(f);
 464  		}
 465  		return sign * INFINITY;
 466  	}
 467  	if (!i) for (i=0; i<3 && (c|32)=="nan"[i]; i++)
 468  		if (i<2) c = shgetc(f);
 469  	if (i==3) {
 470  		if (shgetc(f) != '(') {
 471  			shunget(f);
 472  			return NAN;
 473  		}
 474  		for (i=1; ; i++) {
 475  			c = shgetc(f);
 476  			if (c-'0'<10U || c-'A'<26U || c-'a'<26U || c=='_')
 477  				continue;
 478  			if (c==')') return NAN;
 479  			shunget(f);
 480  			if (!pok) {
 481  				errno = EINVAL;
 482  				shlim(f, 0);
 483  				return 0;
 484  			}
 485  			while (i--) shunget(f);
 486  			return NAN;
 487  		}
 488  		return NAN;
 489  	}
 490  
 491  	if (i) {
 492  		shunget(f);
 493  		errno = EINVAL;
 494  		shlim(f, 0);
 495  		return 0;
 496  	}
 497  
 498  	if (c=='0') {
 499  		c = shgetc(f);
 500  		if ((c|32) == 'x')
 501  			return hexfloat(f, bits, emin, sign, pok);
 502  		shunget(f);
 503  		c = '0';
 504  	}
 505  
 506  	return decfloat(f, c, bits, emin, sign, pok);
 507  }
 508