github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/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(&a, b);
    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  		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  			mppow10flt(&b, dp-ex);
   431  			mpdivfltflt(a, &b);
   432  		}
   433  	}
   434  
   435  out:
   436  	if(f)
   437  		mpnegflt(a);
   438  	return;
   439  
   440  bad:
   441  	yyerror("constant too large: %s", as);
   442  	mpmovecflt(a, 0.0);
   443  }
   444  
   445  //
   446  // fixed point input
   447  // required syntax is [+-][0[x]]d*
   448  //
   449  void
   450  mpatofix(Mpint *a, char *as)
   451  {
   452  	int c, f;
   453  	char *s, *s0;
   454  
   455  	s = as;
   456  	f = 0;
   457  	mpmovecfix(a, 0);
   458  
   459  	c = *s++;
   460  	switch(c) {
   461  	case '-':
   462  		f = 1;
   463  
   464  	case '+':
   465  		c = *s++;
   466  		if(c != '0')
   467  			break;
   468  
   469  	case '0':
   470  		goto oct;
   471  	}
   472  
   473  	while(c) {
   474  		if(c >= '0' && c <= '9') {
   475  			mpmulcfix(a, 10);
   476  			mpaddcfix(a, c-'0');
   477  			c = *s++;
   478  			continue;
   479  		}
   480  		goto bad;
   481  	}
   482  	goto out;
   483  
   484  oct:
   485  	c = *s++;
   486  	if(c == 'x' || c == 'X')
   487  		goto hex;
   488  	while(c) {
   489  		if(c >= '0' && c <= '7') {
   490  			mpmulcfix(a, 8);
   491  			mpaddcfix(a, c-'0');
   492  			c = *s++;
   493  			continue;
   494  		}
   495  		goto bad;
   496  	}
   497  	goto out;
   498  
   499  hex:
   500  	s0 = s;
   501  	c = *s;
   502  	while(c) {
   503  		if((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) {
   504  			s++;
   505  			c = *s;
   506  			continue;
   507  		}
   508  		goto bad;
   509  	}
   510  	mphextofix(a, s0, s-s0);
   511  	if(a->ovf)
   512  		goto bad;
   513  
   514  out:
   515  	if(f)
   516  		mpnegfix(a);
   517  	return;
   518  
   519  bad:
   520  	yyerror("constant too large: %s", as);
   521  	mpmovecfix(a, 0);
   522  }
   523  
   524  int
   525  Bconv(Fmt *fp)
   526  {
   527  	char buf[500], *p;
   528  	Mpint *xval, q, r, ten, sixteen;
   529  	int f, digit;
   530  
   531  	xval = va_arg(fp->args, Mpint*);
   532  	mpmovefixfix(&q, xval);
   533  	f = 0;
   534  	if(mptestfix(&q) < 0) {
   535  		f = 1;
   536  		mpnegfix(&q);
   537  	}
   538  
   539  	p = &buf[sizeof(buf)];
   540  	*--p = 0;
   541  	if(fp->flags & FmtSharp) {
   542  		// Hexadecimal
   543  		mpmovecfix(&sixteen, 16);
   544  		for(;;) {
   545  			mpdivmodfixfix(&q, &r, &q, &sixteen);
   546  			digit = mpgetfix(&r);
   547  			if(digit < 10)
   548  				*--p = digit + '0';
   549  			else
   550  				*--p = digit - 10 + 'A';
   551  			if(mptestfix(&q) <= 0)
   552  				break;
   553  		}
   554  		*--p = 'x';
   555  		*--p = '0';
   556  	} else {
   557  		// Decimal
   558  		mpmovecfix(&ten, 10);
   559  		for(;;) {
   560  			mpdivmodfixfix(&q, &r, &q, &ten);
   561  			*--p = mpgetfix(&r) + '0';
   562  			if(mptestfix(&q) <= 0)
   563  				break;
   564  		}
   565  	}
   566  	if(f)
   567  		*--p = '-';
   568  	return fmtstrcpy(fp, p);
   569  }
   570  
   571  int
   572  Fconv(Fmt *fp)
   573  {
   574  	char buf[500];
   575  	Mpflt *fvp, fv;
   576  	double d;
   577  
   578  	fvp = va_arg(fp->args, Mpflt*);
   579  	if(fp->flags & FmtSharp) {
   580  		// alternate form - decimal for error messages.
   581  		// for well in range, convert to double and use print's %g
   582  		if(-900 < fvp->exp && fvp->exp < 900) {
   583  			d = mpgetflt(fvp);
   584  			if(d >= 0 && (fp->flags & FmtSign))
   585  				fmtprint(fp, "+");
   586  			return fmtprint(fp, "%g", d);
   587  		}
   588  		// TODO(rsc): for well out of range, print
   589  		// an approximation like 1.234e1000
   590  	}
   591  
   592  	if(sigfig(fvp) == 0) {
   593  		snprint(buf, sizeof(buf), "0p+0");
   594  		goto out;
   595  	}
   596  	fv = *fvp;
   597  
   598  	while(fv.val.a[0] == 0) {
   599  		mpshiftfix(&fv.val, -Mpscale);
   600  		fv.exp += Mpscale;
   601  	}
   602  	while((fv.val.a[0]&1) == 0) {
   603  		mpshiftfix(&fv.val, -1);
   604  		fv.exp += 1;
   605  	}
   606  
   607  	if(fv.exp >= 0) {
   608  		snprint(buf, sizeof(buf), "%#Bp+%d", &fv.val, fv.exp);
   609  		goto out;
   610  	}
   611  	snprint(buf, sizeof(buf), "%#Bp-%d", &fv.val, -fv.exp);
   612  
   613  out:
   614  	return fmtstrcpy(fp, buf);
   615  }