github.com/afumu/libc@v0.0.6/musl/src/internal/floatscan.c (about)

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