The Go Programming Language

Text file src/cmd/gc/mparith1.c

     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	"go.h"
     6	
     7	/// uses arithmetic
     8	
     9	int
    10	mpcmpfixflt(Mpint *a, Mpflt *b)
    11	{
    12		char buf[500];
    13		Mpflt c;
    14	
    15		snprint(buf, sizeof(buf), "%B", a);
    16		mpatoflt(&c, buf);
    17		return mpcmpfltflt(&c, b);
    18	}
    19	
    20	int
    21	mpcmpfltfix(Mpflt *a, Mpint *b)
    22	{
    23		char buf[500];
    24		Mpflt c;
    25	
    26		snprint(buf, sizeof(buf), "%B", b);
    27		mpatoflt(&c, buf);
    28		return mpcmpfltflt(a, &c);
    29	}
    30	
    31	int
    32	mpcmpfixfix(Mpint *a, Mpint *b)
    33	{
    34		Mpint c;
    35	
    36		mpmovefixfix(&c, a);
    37		mpsubfixfix(&c, b);
    38		return mptestfix(&c);
    39	}
    40	
    41	int
    42	mpcmpfixc(Mpint *b, vlong c)
    43	{
    44		Mpint a;
    45	
    46		mpmovecfix(&a, c);
    47		return mpcmpfixfix(&a, b);
    48	}
    49	
    50	int
    51	mpcmpfltflt(Mpflt *a, Mpflt *b)
    52	{
    53		Mpflt c;
    54	
    55		mpmovefltflt(&c, a);
    56		mpsubfltflt(&c, b);
    57		return mptestflt(&c);
    58	}
    59	
    60	int
    61	mpcmpfltc(Mpflt *b, double c)
    62	{
    63		Mpflt a;
    64	
    65		mpmovecflt(&a, c);
    66		return mpcmpfltflt(&a, b);
    67	}
    68	
    69	void
    70	mpsubfixfix(Mpint *a, Mpint *b)
    71	{
    72		mpnegfix(a);
    73		mpaddfixfix(a, b);
    74		mpnegfix(a);
    75	}
    76	
    77	void
    78	mpsubfltflt(Mpflt *a, Mpflt *b)
    79	{
    80		mpnegflt(a);
    81		mpaddfltflt(a, b);
    82		mpnegflt(a);
    83	}
    84	
    85	void
    86	mpaddcfix(Mpint *a, vlong c)
    87	{
    88		Mpint b;
    89	
    90		mpmovecfix(&b, c);
    91		mpaddfixfix(a, &b);
    92	}
    93	
    94	void
    95	mpaddcflt(Mpflt *a, double c)
    96	{
    97		Mpflt b;
    98	
    99		mpmovecflt(&b, c);
   100		mpaddfltflt(a, &b);
   101	}
   102	
   103	void
   104	mpmulcfix(Mpint *a, vlong c)
   105	{
   106		Mpint b;
   107	
   108		mpmovecfix(&b, c);
   109		mpmulfixfix(a, &b);
   110	}
   111	
   112	void
   113	mpmulcflt(Mpflt *a, double c)
   114	{
   115		Mpflt b;
   116	
   117		mpmovecflt(&b, c);
   118		mpmulfltflt(a, &b);
   119	}
   120	
   121	void
   122	mpdivfixfix(Mpint *a, Mpint *b)
   123	{
   124		Mpint q, r;
   125	
   126		mpdivmodfixfix(&q, &r, a, b);
   127		mpmovefixfix(a, &q);
   128	}
   129	
   130	void
   131	mpmodfixfix(Mpint *a, Mpint *b)
   132	{
   133		Mpint q, r;
   134	
   135		mpdivmodfixfix(&q, &r, a, b);
   136		mpmovefixfix(a, &r);
   137	}
   138	
   139	void
   140	mpcomfix(Mpint *a)
   141	{
   142		Mpint b;
   143	
   144		mpmovecfix(&b, 1);
   145		mpnegfix(a);
   146		mpsubfixfix(a, &b);
   147	}
   148	
   149	void
   150	mpmovefixflt(Mpflt *a, Mpint *b)
   151	{
   152		a->val = *b;
   153		a->exp = 0;
   154		mpnorm(a);
   155	}
   156	
   157	// convert (truncate) b to a.
   158	// return -1 (but still convert) if b was non-integer.
   159	static int
   160	mpexactfltfix(Mpint *a, Mpflt *b)
   161	{
   162		Mpflt f;
   163	
   164		*a = b->val;
   165		mpshiftfix(a, b->exp);
   166		if(b->exp < 0) {
   167			f.val = *a;
   168			f.exp = 0;
   169			mpnorm(&f);
   170			if(mpcmpfltflt(b, &f) != 0)
   171				return -1;
   172		}
   173		return 0;
   174	}
   175	
   176	int
   177	mpmovefltfix(Mpint *a, Mpflt *b)
   178	{
   179		Mpflt f;
   180		int i;
   181	
   182		if(mpexactfltfix(a, b) == 0)
   183			return 0;
   184	
   185		// try rounding down a little
   186		f = *b;
   187		f.val.a[0] = 0;
   188		if(mpexactfltfix(a, &f) == 0)
   189			return 0;
   190	
   191		// try rounding up a little
   192		for(i=1; i<Mpprec; i++) {
   193			f.val.a[i]++;
   194			if(f.val.a[i] != Mpbase)
   195				break;
   196			f.val.a[i] = 0;
   197		}
   198		mpnorm(&f);
   199		if(mpexactfltfix(a, &f) == 0)
   200			return 0;
   201	
   202		return -1;
   203	}
   204	
   205	void
   206	mpmovefixfix(Mpint *a, Mpint *b)
   207	{
   208		*a = *b;
   209	}
   210	
   211	void
   212	mpmovefltflt(Mpflt *a, Mpflt *b)
   213	{
   214		*a = *b;
   215	}
   216	
   217	static	double	tab[] = { 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7 };
   218	static void
   219	mppow10flt(Mpflt *a, int p)
   220	{
   221		if(p < 0)
   222			abort();
   223		if(p < nelem(tab)) {
   224			mpmovecflt(a, tab[p]);
   225			return;
   226		}
   227		mppow10flt(a, p>>1);
   228		mpmulfltflt(a, a);
   229		if(p & 1)
   230			mpmulcflt(a, 10);
   231	}
   232	
   233	//
   234	// floating point input
   235	// required syntax is [+-]d*[.]d*[e[+-]d*]
   236	//
   237	void
   238	mpatoflt(Mpflt *a, char *as)
   239	{
   240		Mpflt b;
   241		int dp, c, f, ef, ex, eb;
   242		char *s;
   243	
   244		s = as;
   245		dp = 0;		/* digits after decimal point */
   246		f = 0;		/* sign */
   247		ex = 0;		/* exponent */
   248		eb = 0;		/* binary point */
   249	
   250		mpmovecflt(a, 0.0);
   251		for(;;) {
   252			switch(c = *s++) {
   253			default:
   254				goto bad;
   255	
   256			case '-':
   257				f = 1;
   258	
   259			case ' ':
   260			case  '\t':
   261			case  '+':
   262				continue;
   263	
   264			case '.':
   265				dp = 1;
   266				continue;
   267	
   268			case '1':
   269			case '2':
   270			case '3':
   271			case '4':
   272			case '5':
   273			case '6':
   274			case '7':
   275			case '8':
   276			case '9':
   277			case '0':
   278				mpmulcflt(a, 10);
   279				mpaddcflt(a, c-'0');
   280				if(dp)
   281					dp++;
   282				continue;
   283	
   284			case 'P':
   285			case 'p':
   286				eb = 1;
   287	
   288			case 'E':
   289			case 'e':
   290				ex = 0;
   291				ef = 0;
   292				for(;;) {
   293					c = *s++;
   294					if(c == '+' || c == ' ' || c == '\t')
   295						continue;
   296					if(c == '-') {
   297						ef = 1;
   298						continue;
   299					}
   300					if(c >= '0' && c <= '9') {
   301						ex = ex*10 + (c-'0');
   302						if(ex > 1e8) {
   303							yyerror("exponent out of range");
   304							errorexit();
   305						}
   306						continue;
   307					}
   308					break;
   309				}
   310				if(ef)
   311					ex = -ex;
   312	
   313			case 0:
   314				break;
   315			}
   316			break;
   317		}
   318	
   319		if(eb) {
   320			if(dp)
   321				goto bad;
   322			a->exp += ex;
   323			goto out;
   324		}
   325	
   326		if(dp)
   327			dp--;
   328		if(mpcmpfltc(a, 0.0) != 0) {
   329			if(ex >= dp) {
   330				mppow10flt(&b, ex-dp);
   331				mpmulfltflt(a, &b);
   332			} else {
   333				mppow10flt(&b, dp-ex);
   334				mpdivfltflt(a, &b);
   335			}
   336		}
   337	
   338	out:
   339		if(f)
   340			mpnegflt(a);
   341		return;
   342	
   343	bad:
   344		yyerror("set ovf in mpatof");
   345		mpmovecflt(a, 0.0);
   346	}
   347	
   348	//
   349	// fixed point input
   350	// required syntax is [+-][0[x]]d*
   351	//
   352	void
   353	mpatofix(Mpint *a, char *as)
   354	{
   355		int c, f;
   356		char *s;
   357	
   358		s = as;
   359		f = 0;
   360		mpmovecfix(a, 0);
   361	
   362		c = *s++;
   363		switch(c) {
   364		case '-':
   365			f = 1;
   366	
   367		case '+':
   368			c = *s++;
   369			if(c != '0')
   370				break;
   371	
   372		case '0':
   373			goto oct;
   374		}
   375	
   376		while(c) {
   377			if(c >= '0' && c <= '9') {
   378				mpmulcfix(a, 10);
   379				mpaddcfix(a, c-'0');
   380				c = *s++;
   381				continue;
   382			}
   383			goto bad;
   384		}
   385		goto out;
   386	
   387	oct:
   388		c = *s++;
   389		if(c == 'x' || c == 'X')
   390			goto hex;
   391		while(c) {
   392			if(c >= '0' && c <= '7') {
   393				mpmulcfix(a, 8);
   394				mpaddcfix(a, c-'0');
   395				c = *s++;
   396				continue;
   397			}
   398			goto bad;
   399		}
   400		goto out;
   401	
   402	hex:
   403		c = *s++;
   404		while(c) {
   405			if(c >= '0' && c <= '9') {
   406				mpmulcfix(a, 16);
   407				mpaddcfix(a, c-'0');
   408				c = *s++;
   409				continue;
   410			}
   411			if(c >= 'a' && c <= 'f') {
   412				mpmulcfix(a, 16);
   413				mpaddcfix(a, c+10-'a');
   414				c = *s++;
   415				continue;
   416			}
   417			if(c >= 'A' && c <= 'F') {
   418				mpmulcfix(a, 16);
   419				mpaddcfix(a, c+10-'A');
   420				c = *s++;
   421				continue;
   422			}
   423			goto bad;
   424		}
   425	
   426	out:
   427		if(f)
   428			mpnegfix(a);
   429		return;
   430	
   431	bad:
   432		yyerror("set ovf in mpatov: %s", as);
   433		mpmovecfix(a, 0);
   434	}
   435	
   436	int
   437	Bconv(Fmt *fp)
   438	{
   439		char buf[500], *p;
   440		Mpint *xval, q, r, ten;
   441		int f;
   442	
   443		xval = va_arg(fp->args, Mpint*);
   444		mpmovefixfix(&q, xval);
   445		f = 0;
   446		if(mptestfix(&q) < 0) {
   447			f = 1;
   448			mpnegfix(&q);
   449		}
   450		mpmovecfix(&ten, 10);
   451	
   452		p = &buf[sizeof(buf)];
   453		*--p = 0;
   454		for(;;) {
   455			mpdivmodfixfix(&q, &r, &q, &ten);
   456			*--p = mpgetfix(&r) + '0';
   457			if(mptestfix(&q) <= 0)
   458				break;
   459		}
   460		if(f)
   461			*--p = '-';
   462		return fmtstrcpy(fp, p);
   463	}
   464	
   465	int
   466	Fconv(Fmt *fp)
   467	{
   468		char buf[500];
   469		Mpflt *fvp, fv;
   470		double d;
   471	
   472		fvp = va_arg(fp->args, Mpflt*);
   473		if(fp->flags & FmtSharp) {
   474			// alternate form - decimal for error messages.
   475			// for well in range, convert to double and use print's %g
   476			if(-900 < fvp->exp && fvp->exp < 900) {
   477				d = mpgetflt(fvp);
   478				if(d >= 0 && (fp->flags & FmtSign))
   479					fmtprint(fp, "+");
   480				return fmtprint(fp, "%g", d);
   481			}
   482			// TODO(rsc): for well out of range, print
   483			// an approximation like 1.234e1000
   484		}
   485	
   486		if(sigfig(fvp) == 0) {
   487			snprint(buf, sizeof(buf), "0p+0");
   488			goto out;
   489		}
   490		fv = *fvp;
   491	
   492		while(fv.val.a[0] == 0) {
   493			mpshiftfix(&fv.val, -Mpscale);
   494			fv.exp += Mpscale;
   495		}
   496		while((fv.val.a[0]&1) == 0) {
   497			mpshiftfix(&fv.val, -1);
   498			fv.exp += 1;
   499		}
   500	
   501		if(fv.exp >= 0) {
   502			snprint(buf, sizeof(buf), "%Bp+%d", &fv.val, fv.exp);
   503			goto out;
   504		}
   505		snprint(buf, sizeof(buf), "%Bp-%d", &fv.val, -fv.exp);
   506	
   507	out:
   508		return fmtstrcpy(fp, buf);
   509	}

release.r60.3. Except as noted, this content is licensed under a Creative Commons Attribution 3.0 License.