github.com/yanyiwu/go@v0.0.0-20150106053140-03d6637dbb7f/src/cmd/gc/mparith1.c (about)

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  #include	<u.h>
     6  #include	<libc.h>
     7  #include	"go.h"
     8  
     9  /// uses arithmetic
    10  
    11  int
    12  mpcmpfixflt(Mpint *a, Mpflt *b)
    13  {
    14  	char buf[500];
    15  	Mpflt c;
    16  
    17  	snprint(buf, sizeof(buf), "%B", a);
    18  	mpatoflt(&c, buf);
    19  	return mpcmpfltflt(&c, b);
    20  }
    21  
    22  int
    23  mpcmpfltfix(Mpflt *a, Mpint *b)
    24  {
    25  	char buf[500];
    26  	Mpflt c;
    27  
    28  	snprint(buf, sizeof(buf), "%B", b);
    29  	mpatoflt(&c, buf);
    30  	return mpcmpfltflt(a, &c);
    31  }
    32  
    33  int
    34  mpcmpfixfix(Mpint *a, Mpint *b)
    35  {
    36  	Mpint c;
    37  
    38  	mpmovefixfix(&c, a);
    39  	mpsubfixfix(&c, b);
    40  	return mptestfix(&c);
    41  }
    42  
    43  int
    44  mpcmpfixc(Mpint *b, vlong c)
    45  {
    46  	Mpint c1;
    47  
    48  	mpmovecfix(&c1, c);
    49  	return mpcmpfixfix(b, &c1);
    50  }
    51  
    52  int
    53  mpcmpfltflt(Mpflt *a, Mpflt *b)
    54  {
    55  	Mpflt c;
    56  
    57  	mpmovefltflt(&c, a);
    58  	mpsubfltflt(&c, b);
    59  	return mptestflt(&c);
    60  }
    61  
    62  int
    63  mpcmpfltc(Mpflt *b, double c)
    64  {
    65  	Mpflt a;
    66  
    67  	mpmovecflt(&a, c);
    68  	return mpcmpfltflt(b, &a);
    69  }
    70  
    71  void
    72  mpsubfixfix(Mpint *a, Mpint *b)
    73  {
    74  	mpnegfix(a);
    75  	mpaddfixfix(a, b, 0);
    76  	mpnegfix(a);
    77  }
    78  
    79  void
    80  mpsubfltflt(Mpflt *a, Mpflt *b)
    81  {
    82  	mpnegflt(a);
    83  	mpaddfltflt(a, b);
    84  	mpnegflt(a);
    85  }
    86  
    87  void
    88  mpaddcfix(Mpint *a, vlong c)
    89  {
    90  	Mpint b;
    91  
    92  	mpmovecfix(&b, c);
    93  	mpaddfixfix(a, &b, 0);
    94  }
    95  
    96  void
    97  mpaddcflt(Mpflt *a, double c)
    98  {
    99  	Mpflt b;
   100  
   101  	mpmovecflt(&b, c);
   102  	mpaddfltflt(a, &b);
   103  }
   104  
   105  void
   106  mpmulcfix(Mpint *a, vlong c)
   107  {
   108  	Mpint b;
   109  
   110  	mpmovecfix(&b, c);
   111  	mpmulfixfix(a, &b);
   112  }
   113  
   114  void
   115  mpmulcflt(Mpflt *a, double c)
   116  {
   117  	Mpflt b;
   118  
   119  	mpmovecflt(&b, c);
   120  	mpmulfltflt(a, &b);
   121  }
   122  
   123  void
   124  mpdivfixfix(Mpint *a, Mpint *b)
   125  {
   126  	Mpint q, r;
   127  
   128  	mpdivmodfixfix(&q, &r, a, b);
   129  	mpmovefixfix(a, &q);
   130  }
   131  
   132  void
   133  mpmodfixfix(Mpint *a, Mpint *b)
   134  {
   135  	Mpint q, r;
   136  
   137  	mpdivmodfixfix(&q, &r, a, b);
   138  	mpmovefixfix(a, &r);
   139  }
   140  
   141  void
   142  mpcomfix(Mpint *a)
   143  {
   144  	Mpint b;
   145  
   146  	mpmovecfix(&b, 1);
   147  	mpnegfix(a);
   148  	mpsubfixfix(a, &b);
   149  }
   150  
   151  void
   152  mpmovefixflt(Mpflt *a, Mpint *b)
   153  {
   154  	a->val = *b;
   155  	a->exp = 0;
   156  	mpnorm(a);
   157  }
   158  
   159  // convert (truncate) b to a.
   160  // return -1 (but still convert) if b was non-integer.
   161  static int
   162  mpexactfltfix(Mpint *a, Mpflt *b)
   163  {
   164  	Mpflt f;
   165  
   166  	*a = b->val;
   167  	mpshiftfix(a, b->exp);
   168  	if(b->exp < 0) {
   169  		f.val = *a;
   170  		f.exp = 0;
   171  		mpnorm(&f);
   172  		if(mpcmpfltflt(b, &f) != 0)
   173  			return -1;
   174  	}
   175  	return 0;
   176  }
   177  
   178  int
   179  mpmovefltfix(Mpint *a, Mpflt *b)
   180  {
   181  	Mpflt f;
   182  	int i;
   183  
   184  	if(mpexactfltfix(a, b) == 0)
   185  		return 0;
   186  
   187  	// try rounding down a little
   188  	f = *b;
   189  	f.val.a[0] = 0;
   190  	if(mpexactfltfix(a, &f) == 0)
   191  		return 0;
   192  
   193  	// try rounding up a little
   194  	for(i=1; i<Mpprec; i++) {
   195  		f.val.a[i]++;
   196  		if(f.val.a[i] != Mpbase)
   197  			break;
   198  		f.val.a[i] = 0;
   199  	}
   200  	mpnorm(&f);
   201  	if(mpexactfltfix(a, &f) == 0)
   202  		return 0;
   203  
   204  	return -1;
   205  }
   206  
   207  void
   208  mpmovefixfix(Mpint *a, Mpint *b)
   209  {
   210  	*a = *b;
   211  }
   212  
   213  void
   214  mpmovefltflt(Mpflt *a, Mpflt *b)
   215  {
   216  	*a = *b;
   217  }
   218  
   219  static	double	tab[] = { 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7 };
   220  static void
   221  mppow10flt(Mpflt *a, int p)
   222  {
   223  	if(p < 0)
   224  		abort();
   225  	if(p < nelem(tab)) {
   226  		mpmovecflt(a, tab[p]);
   227  		return;
   228  	}
   229  	mppow10flt(a, p>>1);
   230  	mpmulfltflt(a, a);
   231  	if(p & 1)
   232  		mpmulcflt(a, 10);
   233  }
   234  
   235  static void
   236  mphextofix(Mpint *a, char *s, int n)
   237  {
   238  	char *hexdigitp, *end, c;
   239  	long d;
   240  	int bit;
   241  
   242  	while(*s == '0') {
   243  		s++;
   244  		n--;
   245  	}
   246  
   247  	// overflow
   248  	if(4*n > Mpscale*Mpprec) {
   249  		a->ovf = 1;
   250  		return;
   251  	}
   252  
   253  	end = s+n-1;
   254  	for(hexdigitp=end; hexdigitp>=s; hexdigitp--) {
   255  		c = *hexdigitp;
   256  		if(c >= '0' && c <= '9')
   257  			d = c-'0';
   258  		else if(c >= 'A' && c <= 'F')
   259  			d = c-'A'+10;
   260  		else
   261  			d = c-'a'+10;
   262  
   263  		bit = 4*(end - hexdigitp);
   264  		while(d > 0) {
   265  			if(d & 1)
   266  				a->a[bit/Mpscale] |= (long)1 << (bit%Mpscale);
   267  			bit++;
   268  			d = d >> 1;
   269  		}
   270  	}
   271  }
   272  
   273  //
   274  // floating point input
   275  // required syntax is [+-]d*[.]d*[e[+-]d*] or [+-]0xH*[e[+-]d*]
   276  //
   277  void
   278  mpatoflt(Mpflt *a, char *as)
   279  {
   280  	Mpflt b;
   281  	int dp, c, f, ef, ex, eb, base;
   282  	char *s, *start;
   283  
   284  	while(*as == ' ' || *as == '\t')
   285  		as++;
   286  
   287  	/* determine base */
   288  	s = as;
   289  	base = -1;
   290  	while(base == -1) {
   291  		switch(*s++) {
   292  		case '-':
   293  		case '+':
   294  			break;
   295  
   296  		case '0':
   297  			if(*s == 'x')
   298  				base = 16;
   299  			else
   300  				base = 10;
   301  			break;
   302  
   303  		default:
   304  			base = 10;
   305  		}
   306  	}
   307  
   308  	s = as;
   309  	dp = 0;		/* digits after decimal point */
   310  	f = 0;		/* sign */
   311  	ex = 0;		/* exponent */
   312  	eb = 0;		/* binary point */
   313  
   314  	mpmovecflt(a, 0.0);
   315  	if(base == 16) {
   316  		start = nil;
   317  		for(;;) {
   318  			c = *s;
   319  			if(c == '-') {
   320  				f = 1;
   321  				s++;
   322  			}
   323  			else if(c == '+') {
   324  				s++;
   325  			}
   326  			else if(c == '0' && s[1] == 'x') {
   327  				s += 2;
   328  				start = s;
   329  			}
   330  			else if((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) {
   331  				s++;
   332  			}
   333  			else {
   334  				break;
   335  			}
   336  		}
   337  		if(start == nil)
   338  			goto bad;
   339  
   340  		mphextofix(&a->val, start, s-start);
   341  		if(a->val.ovf)
   342  			goto bad;
   343  		a->exp = 0;
   344  		mpnorm(a);
   345  	}
   346  	for(;;) {
   347  		switch(c = *s++) {
   348  		default:
   349  			goto bad;
   350  
   351  		case '-':
   352  			f = 1;
   353  
   354  		case ' ':
   355  		case '\t':
   356  		case '+':
   357  			continue;
   358  
   359  		case '.':
   360  			if(base == 16)
   361  				goto bad;
   362  			dp = 1;
   363  			continue;
   364  
   365  		case '1':
   366  		case '2':
   367  		case '3':
   368  		case '4':
   369  		case '5':
   370  		case '6':
   371  		case '7':
   372  		case '8':
   373  		case '9':
   374  		case '0':
   375  			mpmulcflt(a, 10);
   376  			mpaddcflt(a, c-'0');
   377  			if(dp)
   378  				dp++;
   379  			continue;
   380  
   381  		case 'P':
   382  		case 'p':
   383  			eb = 1;
   384  
   385  		case 'E':
   386  		case 'e':
   387  			ex = 0;
   388  			ef = 0;
   389  			for(;;) {
   390  				c = *s++;
   391  				if(c == '+' || c == ' ' || c == '\t')
   392  					continue;
   393  				if(c == '-') {
   394  					ef = 1;
   395  					continue;
   396  				}
   397  				if(c >= '0' && c <= '9') {
   398  					ex = ex*10 + (c-'0');
   399  					if(ex > 1e8) {
   400  						yyerror("constant exponent out of range: %s", as);
   401  						errorexit();
   402  					}
   403  					continue;
   404  				}
   405  				break;
   406  			}
   407  			if(ef)
   408  				ex = -ex;
   409  
   410  		case 0:
   411  			break;
   412  		}
   413  		break;
   414  	}
   415  
   416  	if(eb) {
   417  		if(dp)
   418  			goto bad;
   419  		mpsetexp(a, a->exp+ex);
   420  		goto out;
   421  	}
   422  
   423  	if(dp)
   424  		dp--;
   425  	if(mpcmpfltc(a, 0.0) != 0) {
   426  		if(ex >= dp) {
   427  			mppow10flt(&b, ex-dp);
   428  			mpmulfltflt(a, &b);
   429  		} else {
   430  			// 4 approximates least_upper_bound(log2(10)).
   431  			if(dp-ex >= (1<<(8*sizeof(dp)-3)) || (short)(4*(dp-ex)) != 4*(dp-ex)) {
   432  				mpmovecflt(a, 0.0);
   433  			}
   434  			else {
   435  				mppow10flt(&b, dp-ex);
   436  				mpdivfltflt(a, &b);
   437  			}
   438  		}
   439  	}
   440  
   441  out:
   442  	if(f)
   443  		mpnegflt(a);
   444  	return;
   445  
   446  bad:
   447  	yyerror("constant too large: %s", as);
   448  	mpmovecflt(a, 0.0);
   449  }
   450  
   451  //
   452  // fixed point input
   453  // required syntax is [+-][0[x]]d*
   454  //
   455  void
   456  mpatofix(Mpint *a, char *as)
   457  {
   458  	int c, f;
   459  	char *s, *s0;
   460  
   461  	s = as;
   462  	f = 0;
   463  	mpmovecfix(a, 0);
   464  
   465  	c = *s++;
   466  	switch(c) {
   467  	case '-':
   468  		f = 1;
   469  
   470  	case '+':
   471  		c = *s++;
   472  		if(c != '0')
   473  			break;
   474  
   475  	case '0':
   476  		goto oct;
   477  	}
   478  
   479  	while(c) {
   480  		if(c >= '0' && c <= '9') {
   481  			mpmulcfix(a, 10);
   482  			mpaddcfix(a, c-'0');
   483  			c = *s++;
   484  			continue;
   485  		}
   486  		goto bad;
   487  	}
   488  	goto out;
   489  
   490  oct:
   491  	c = *s++;
   492  	if(c == 'x' || c == 'X')
   493  		goto hex;
   494  	while(c) {
   495  		if(c >= '0' && c <= '7') {
   496  			mpmulcfix(a, 8);
   497  			mpaddcfix(a, c-'0');
   498  			c = *s++;
   499  			continue;
   500  		}
   501  		goto bad;
   502  	}
   503  	goto out;
   504  
   505  hex:
   506  	s0 = s;
   507  	c = *s;
   508  	while(c) {
   509  		if((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) {
   510  			s++;
   511  			c = *s;
   512  			continue;
   513  		}
   514  		goto bad;
   515  	}
   516  	mphextofix(a, s0, s-s0);
   517  	if(a->ovf)
   518  		goto bad;
   519  
   520  out:
   521  	if(f)
   522  		mpnegfix(a);
   523  	return;
   524  
   525  bad:
   526  	yyerror("constant too large: %s", as);
   527  	mpmovecfix(a, 0);
   528  }
   529  
   530  int
   531  Bconv(Fmt *fp)
   532  {
   533  	char buf[500], *p;
   534  	Mpint *xval, q, r, ten, sixteen;
   535  	int f, digit;
   536  
   537  	xval = va_arg(fp->args, Mpint*);
   538  	mpmovefixfix(&q, xval);
   539  	f = 0;
   540  	if(mptestfix(&q) < 0) {
   541  		f = 1;
   542  		mpnegfix(&q);
   543  	}
   544  
   545  	p = &buf[sizeof(buf)];
   546  	*--p = 0;
   547  	if(fp->flags & FmtSharp) {
   548  		// Hexadecimal
   549  		mpmovecfix(&sixteen, 16);
   550  		for(;;) {
   551  			mpdivmodfixfix(&q, &r, &q, &sixteen);
   552  			digit = mpgetfix(&r);
   553  			if(digit < 10)
   554  				*--p = digit + '0';
   555  			else
   556  				*--p = digit - 10 + 'A';
   557  			if(mptestfix(&q) <= 0)
   558  				break;
   559  		}
   560  		*--p = 'x';
   561  		*--p = '0';
   562  	} else {
   563  		// Decimal
   564  		mpmovecfix(&ten, 10);
   565  		for(;;) {
   566  			mpdivmodfixfix(&q, &r, &q, &ten);
   567  			*--p = mpgetfix(&r) + '0';
   568  			if(mptestfix(&q) <= 0)
   569  				break;
   570  		}
   571  	}
   572  	if(f)
   573  		*--p = '-';
   574  	return fmtstrcpy(fp, p);
   575  }
   576  
   577  int
   578  Fconv(Fmt *fp)
   579  {
   580  	char buf[500];
   581  	Mpflt *fvp, fv;
   582  	double d, dexp;
   583  	int exp;
   584  
   585  	fvp = va_arg(fp->args, Mpflt*);
   586  	if(fp->flags & FmtSharp) {
   587  		// alternate form - decimal for error messages.
   588  		// for well in range, convert to double and use print's %g
   589  		exp = fvp->exp + sigfig(fvp)*Mpscale;
   590  		if(-900 < exp && exp < 900) {
   591  			d = mpgetflt(fvp);
   592  			if(d >= 0 && (fp->flags & FmtSign))
   593  				fmtprint(fp, "+");
   594  			return fmtprint(fp, "%g", d);
   595  		}
   596  		
   597  		// very out of range. compute decimal approximation by hand.
   598  		// decimal exponent
   599  		dexp = fvp->exp * 0.301029995663981195; // log_10(2)
   600  		exp = (int)dexp;
   601  		// decimal mantissa
   602  		fv = *fvp;
   603  		fv.val.neg = 0;
   604  		fv.exp = 0;
   605  		d = mpgetflt(&fv);
   606  		d *= pow(10, dexp-exp);
   607  		while(d >= 9.99995) {
   608  			d /= 10;
   609  			exp++;
   610  		}
   611  		if(fvp->val.neg)
   612  			fmtprint(fp, "-");
   613  		else if(fp->flags & FmtSign)
   614  			fmtprint(fp, "+");
   615  		return fmtprint(fp, "%.5fe+%d", d, exp);
   616  	}
   617  
   618  	if(sigfig(fvp) == 0) {
   619  		snprint(buf, sizeof(buf), "0p+0");
   620  		goto out;
   621  	}
   622  	fv = *fvp;
   623  
   624  	while(fv.val.a[0] == 0) {
   625  		mpshiftfix(&fv.val, -Mpscale);
   626  		fv.exp += Mpscale;
   627  	}
   628  	while((fv.val.a[0]&1) == 0) {
   629  		mpshiftfix(&fv.val, -1);
   630  		fv.exp += 1;
   631  	}
   632  
   633  	if(fv.exp >= 0) {
   634  		snprint(buf, sizeof(buf), "%#Bp+%d", &fv.val, fv.exp);
   635  		goto out;
   636  	}
   637  	snprint(buf, sizeof(buf), "%#Bp-%d", &fv.val, -fv.exp);
   638  
   639  out:
   640  	return fmtstrcpy(fp, buf);
   641  }