github.com/yanyiwu/go@v0.0.0-20150106053140-03d6637dbb7f/src/cmd/gc/mparith3.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  /*
    10   * returns the leading non-zero
    11   * word of the number
    12   */
    13  int
    14  sigfig(Mpflt *a)
    15  {
    16  	int i;
    17  
    18  	for(i=Mpprec-1; i>=0; i--)
    19  		if(a->val.a[i] != 0)
    20  			break;
    21  //print("sigfig %d %d\n", i-z+1, z);
    22  	return i+1;
    23  }
    24  
    25  /*
    26   * sets the exponent.
    27   * a too large exponent is an error.
    28   * a too small exponent rounds the number to zero.
    29   */
    30  void
    31  mpsetexp(Mpflt *a, int exp) {
    32  	if((short)exp != exp) {
    33  		if(exp > 0) {
    34  			yyerror("float constant is too large");
    35  			a->exp = 0x7fff;
    36  		}
    37  		else {
    38  			mpmovecflt(a, 0);
    39  		}
    40  	}
    41  	else {
    42  		a->exp = exp;
    43  	}
    44  }
    45  
    46  /*
    47   * shifts the leading non-zero
    48   * word of the number to Mpnorm
    49   */
    50  void
    51  mpnorm(Mpflt *a)
    52  {
    53  	int s, os;
    54  	long x;
    55  
    56  	os = sigfig(a);
    57  	if(os == 0) {
    58  		// zero
    59  		a->exp = 0;
    60  		a->val.neg = 0;
    61  		return;
    62  	}
    63  
    64  	// this will normalize to the nearest word
    65  	x = a->val.a[os-1];
    66  	s = (Mpnorm-os) * Mpscale;
    67  
    68  	// further normalize to the nearest bit
    69  	for(;;) {
    70  		x <<= 1;
    71  		if(x & Mpbase)
    72  			break;
    73  		s++;
    74  		if(x == 0) {
    75  			// this error comes from trying to
    76  			// convert an Inf or something
    77  			// where the initial x=0x80000000
    78  			s = (Mpnorm-os) * Mpscale;
    79  			break;
    80  		}
    81  	}
    82  
    83  	mpshiftfix(&a->val, s);
    84  	mpsetexp(a, a->exp-s);
    85  }
    86  
    87  /// implements float arihmetic
    88  
    89  void
    90  mpaddfltflt(Mpflt *a, Mpflt *b)
    91  {
    92  	int sa, sb, s;
    93  	Mpflt c;
    94  
    95  	if(Mpdebug)
    96  		print("\n%F + %F", a, b);
    97  
    98  	sa = sigfig(a);
    99  	if(sa == 0) {
   100  		mpmovefltflt(a, b);
   101  		goto out;
   102  	}
   103  
   104  	sb = sigfig(b);
   105  	if(sb == 0)
   106  		goto out;
   107  
   108  	s = a->exp - b->exp;
   109  	if(s > 0) {
   110  		// a is larger, shift b right
   111  		mpmovefltflt(&c, b);
   112  		mpshiftfix(&c.val, -s);
   113  		mpaddfixfix(&a->val, &c.val, 0);
   114  		goto out;
   115  	}
   116  	if(s < 0) {
   117  		// b is larger, shift a right
   118  		mpshiftfix(&a->val, s);
   119  		mpsetexp(a, a->exp-s);
   120  		mpaddfixfix(&a->val, &b->val, 0);
   121  		goto out;
   122  	}
   123  	mpaddfixfix(&a->val, &b->val, 0);
   124  
   125  out:
   126  	mpnorm(a);
   127  	if(Mpdebug)
   128  		print(" = %F\n\n", a);
   129  }
   130  
   131  void
   132  mpmulfltflt(Mpflt *a, Mpflt *b)
   133  {
   134  	int sa, sb;
   135  
   136  	if(Mpdebug)
   137  		print("%F\n * %F\n", a, b);
   138  
   139  	sa = sigfig(a);
   140  	if(sa == 0) {
   141  		// zero
   142  		a->exp = 0;
   143  		a->val.neg = 0;
   144  		return;
   145  	}
   146  
   147  	sb = sigfig(b);
   148  	if(sb == 0) {
   149  		// zero
   150  		mpmovefltflt(a, b);
   151  		return;
   152  	}
   153  
   154  	mpmulfract(&a->val, &b->val);
   155  	mpsetexp(a, (a->exp + b->exp) + Mpscale*Mpprec - Mpscale - 1);
   156  
   157  	mpnorm(a);
   158  	if(Mpdebug)
   159  		print(" = %F\n\n", a);
   160  }
   161  
   162  void
   163  mpdivfltflt(Mpflt *a, Mpflt *b)
   164  {
   165  	int sa, sb;
   166  	Mpflt c;
   167  
   168  	if(Mpdebug)
   169  		print("%F\n / %F\n", a, b);
   170  
   171  	sb = sigfig(b);
   172  	if(sb == 0) {
   173  		// zero and ovfl
   174  		a->exp = 0;
   175  		a->val.neg = 0;
   176  		a->val.ovf = 1;
   177  		yyerror("constant division by zero");
   178  		return;
   179  	}
   180  
   181  	sa = sigfig(a);
   182  	if(sa == 0) {
   183  		// zero
   184  		a->exp = 0;
   185  		a->val.neg = 0;
   186  		return;
   187  	}
   188  
   189  	// adjust b to top
   190  	mpmovefltflt(&c, b);
   191  	mpshiftfix(&c.val, Mpscale);
   192  
   193  	// divide
   194  	mpdivfract(&a->val, &c.val);
   195  	mpsetexp(a, (a->exp-c.exp) - Mpscale*(Mpprec-1) + 1);
   196  
   197  	mpnorm(a);
   198  	if(Mpdebug)
   199  		print(" = %F\n\n", a);
   200  }
   201  
   202  static double
   203  mpgetfltN(Mpflt *a, int prec, int bias)
   204  {
   205  	int s, i, e, minexp;
   206  	uvlong v;
   207  	double f;
   208  
   209  	if(a->val.ovf && nsavederrors+nerrors == 0)
   210  		yyerror("mpgetflt ovf");
   211  
   212  	s = sigfig(a);
   213  	if(s == 0)
   214  		return 0;
   215  
   216  	if(s != Mpnorm) {
   217  		yyerror("mpgetflt norm");
   218  		mpnorm(a);
   219  	}
   220  
   221  	while((a->val.a[Mpnorm-1] & Mpsign) == 0) {
   222  		mpshiftfix(&a->val, 1);
   223  		mpsetexp(a, a->exp-1);	// can set 'a' to zero
   224  		s = sigfig(a);
   225  		if(s == 0)
   226  			return 0;
   227  	}
   228  
   229  	// pick up the mantissa, a rounding bit, and a tie-breaking bit in a uvlong
   230  	s = prec+2;
   231  	v = 0;
   232  	for(i=Mpnorm-1; s>=Mpscale; i--) {
   233  		v = (v<<Mpscale) | a->val.a[i];
   234  		s -= Mpscale;
   235  	}
   236  	if(s > 0) {
   237  		v = (v<<s) | (a->val.a[i]>>(Mpscale-s));
   238  		if((a->val.a[i]&((1<<(Mpscale-s))-1)) != 0)
   239  			v |= 1;
   240  		i--;
   241  	}
   242  	for(; i >= 0; i--) {
   243  		if(a->val.a[i] != 0)
   244  			v |= 1;
   245  	}
   246  
   247  	// gradual underflow
   248  	e = Mpnorm*Mpscale + a->exp - prec;
   249  	minexp = bias+1-prec+1;
   250  	if(e < minexp) {
   251  		s = minexp - e;
   252  		if(s > prec+1)
   253  			s = prec+1;
   254  		if((v & ((1ULL<<s)-1)) != 0)
   255  			v |= 1ULL<<s;
   256  		v >>= s;
   257  		e = minexp;
   258  	}
   259  	
   260  	// round to even
   261  	v |= (v&4)>>2;
   262  	v += v&1;
   263  	v >>= 2;
   264  
   265  	f = (double)(v);
   266  	f = ldexp(f, e);
   267  
   268  	if(a->val.neg)
   269  		f = -f;
   270  
   271  	return f;
   272  }
   273  
   274  double
   275  mpgetflt(Mpflt *a)
   276  {
   277  	return mpgetfltN(a, 53, -1023);
   278  }
   279  
   280  double
   281  mpgetflt32(Mpflt *a)
   282  {
   283  	return mpgetfltN(a, 24, -127);
   284  }
   285  
   286  void
   287  mpmovecflt(Mpflt *a, double c)
   288  {
   289  	int i;
   290  	double f;
   291  	long l;
   292  
   293  	if(Mpdebug)
   294  		print("\nconst %g", c);
   295  	mpmovecfix(&a->val, 0);
   296  	a->exp = 0;
   297  	if(c == 0)
   298  		goto out;
   299  	if(c < 0) {
   300  		a->val.neg = 1;
   301  		c = -c;
   302  	}
   303  
   304  	f = frexp(c, &i);
   305  	a->exp = i;
   306  
   307  	for(i=0; i<10; i++) {
   308  		f = f*Mpbase;
   309  		l = floor(f);
   310  		f = f - l;
   311  		a->exp -= Mpscale;
   312  		a->val.a[0] = l;
   313  		if(f == 0)
   314  			break;
   315  		mpshiftfix(&a->val, Mpscale);
   316  	}
   317  
   318  out:
   319  	mpnorm(a);
   320  	if(Mpdebug)
   321  		print(" = %F\n", a);
   322  }
   323  
   324  void
   325  mpnegflt(Mpflt *a)
   326  {
   327  	a->val.neg ^= 1;
   328  }
   329  
   330  int
   331  mptestflt(Mpflt *a)
   332  {
   333  	int s;
   334  
   335  	if(Mpdebug)
   336  		print("\n%F?", a);
   337  	s = sigfig(a);
   338  	if(s != 0) {
   339  		s = +1;
   340  		if(a->val.neg)
   341  			s = -1;
   342  	}
   343  	if(Mpdebug)
   344  		print(" = %d\n", s);
   345  	return s;
   346  }