github.com/rsc/tmp@v0.0.0-20240517235954-6deaab19748b/bootstrap/internal/gc/big/arith.go (about)

     1  // Do not edit. Bootstrap copy of /Users/rsc/g/go/src/cmd/internal/gc/big/arith.go
     2  
     3  // Copyright 2009 The Go Authors. All rights reserved.
     4  // Use of this source code is governed by a BSD-style
     5  // license that can be found in the LICENSE file.
     6  
     7  // This file provides Go implementations of elementary multi-precision
     8  // arithmetic operations on word vectors. Needed for platforms without
     9  // assembly implementations of these routines.
    10  
    11  package big
    12  
    13  // A Word represents a single digit of a multi-precision unsigned integer.
    14  type Word uintptr
    15  
    16  const (
    17  	// Compute the size _S of a Word in bytes.
    18  	_m    = ^Word(0)
    19  	_logS = _m>>8&1 + _m>>16&1 + _m>>32&1
    20  	_S    = 1 << _logS
    21  
    22  	_W = _S << 3 // word size in bits
    23  	_B = 1 << _W // digit base
    24  	_M = _B - 1  // digit mask
    25  
    26  	_W2 = _W / 2   // half word size in bits
    27  	_B2 = 1 << _W2 // half digit base
    28  	_M2 = _B2 - 1  // half digit mask
    29  )
    30  
    31  // ----------------------------------------------------------------------------
    32  // Elementary operations on words
    33  //
    34  // These operations are used by the vector operations below.
    35  
    36  // z1<<_W + z0 = x+y+c, with c == 0 or 1
    37  func addWW_g(x, y, c Word) (z1, z0 Word) {
    38  	yc := y + c
    39  	z0 = x + yc
    40  	if z0 < x || yc < y {
    41  		z1 = 1
    42  	}
    43  	return
    44  }
    45  
    46  // z1<<_W + z0 = x-y-c, with c == 0 or 1
    47  func subWW_g(x, y, c Word) (z1, z0 Word) {
    48  	yc := y + c
    49  	z0 = x - yc
    50  	if z0 > x || yc < y {
    51  		z1 = 1
    52  	}
    53  	return
    54  }
    55  
    56  // z1<<_W + z0 = x*y
    57  // Adapted from Warren, Hacker's Delight, p. 132.
    58  func mulWW_g(x, y Word) (z1, z0 Word) {
    59  	x0 := x & _M2
    60  	x1 := x >> _W2
    61  	y0 := y & _M2
    62  	y1 := y >> _W2
    63  	w0 := x0 * y0
    64  	t := x1*y0 + w0>>_W2
    65  	w1 := t & _M2
    66  	w2 := t >> _W2
    67  	w1 += x0 * y1
    68  	z1 = x1*y1 + w2 + w1>>_W2
    69  	z0 = x * y
    70  	return
    71  }
    72  
    73  // z1<<_W + z0 = x*y + c
    74  func mulAddWWW_g(x, y, c Word) (z1, z0 Word) {
    75  	z1, zz0 := mulWW_g(x, y)
    76  	if z0 = zz0 + c; z0 < zz0 {
    77  		z1++
    78  	}
    79  	return
    80  }
    81  
    82  // Length of x in bits.
    83  func bitLen_g(x Word) (n int) {
    84  	for ; x >= 0x8000; x >>= 16 {
    85  		n += 16
    86  	}
    87  	if x >= 0x80 {
    88  		x >>= 8
    89  		n += 8
    90  	}
    91  	if x >= 0x8 {
    92  		x >>= 4
    93  		n += 4
    94  	}
    95  	if x >= 0x2 {
    96  		x >>= 2
    97  		n += 2
    98  	}
    99  	if x >= 0x1 {
   100  		n++
   101  	}
   102  	return
   103  }
   104  
   105  // log2 computes the integer binary logarithm of x.
   106  // The result is the integer n for which 2^n <= x < 2^(n+1).
   107  // If x == 0, the result is -1.
   108  func log2(x Word) int {
   109  	return bitLen(x) - 1
   110  }
   111  
   112  // Number of leading zeros in x.
   113  func leadingZeros(x Word) uint {
   114  	return uint(_W - bitLen(x))
   115  }
   116  
   117  // q = (u1<<_W + u0 - r)/y
   118  // Adapted from Warren, Hacker's Delight, p. 152.
   119  func divWW_g(u1, u0, v Word) (q, r Word) {
   120  	if u1 >= v {
   121  		return 1<<_W - 1, 1<<_W - 1
   122  	}
   123  
   124  	s := leadingZeros(v)
   125  	v <<= s
   126  
   127  	vn1 := v >> _W2
   128  	vn0 := v & _M2
   129  	un32 := u1<<s | u0>>(_W-s)
   130  	un10 := u0 << s
   131  	un1 := un10 >> _W2
   132  	un0 := un10 & _M2
   133  	q1 := un32 / vn1
   134  	rhat := un32 - q1*vn1
   135  
   136  	for q1 >= _B2 || q1*vn0 > _B2*rhat+un1 {
   137  		q1--
   138  		rhat += vn1
   139  		if rhat >= _B2 {
   140  			break
   141  		}
   142  	}
   143  
   144  	un21 := un32*_B2 + un1 - q1*v
   145  	q0 := un21 / vn1
   146  	rhat = un21 - q0*vn1
   147  
   148  	for q0 >= _B2 || q0*vn0 > _B2*rhat+un0 {
   149  		q0--
   150  		rhat += vn1
   151  		if rhat >= _B2 {
   152  			break
   153  		}
   154  	}
   155  
   156  	return q1*_B2 + q0, (un21*_B2 + un0 - q0*v) >> s
   157  }
   158  
   159  // Keep for performance debugging.
   160  // Using addWW_g is likely slower.
   161  const use_addWW_g = false
   162  
   163  // The resulting carry c is either 0 or 1.
   164  func addVV_g(z, x, y []Word) (c Word) {
   165  	if use_addWW_g {
   166  		for i := range z {
   167  			c, z[i] = addWW_g(x[i], y[i], c)
   168  		}
   169  		return
   170  	}
   171  
   172  	for i, xi := range x[:len(z)] {
   173  		yi := y[i]
   174  		zi := xi + yi + c
   175  		z[i] = zi
   176  		// see "Hacker's Delight", section 2-12 (overflow detection)
   177  		c = (xi&yi | (xi|yi)&^zi) >> (_W - 1)
   178  	}
   179  	return
   180  }
   181  
   182  // The resulting carry c is either 0 or 1.
   183  func subVV_g(z, x, y []Word) (c Word) {
   184  	if use_addWW_g {
   185  		for i := range z {
   186  			c, z[i] = subWW_g(x[i], y[i], c)
   187  		}
   188  		return
   189  	}
   190  
   191  	for i, xi := range x[:len(z)] {
   192  		yi := y[i]
   193  		zi := xi - yi - c
   194  		z[i] = zi
   195  		// see "Hacker's Delight", section 2-12 (overflow detection)
   196  		c = (yi&^xi | (yi|^xi)&zi) >> (_W - 1)
   197  	}
   198  	return
   199  }
   200  
   201  // Argument y must be either 0 or 1.
   202  // The resulting carry c is either 0 or 1.
   203  func addVW_g(z, x []Word, y Word) (c Word) {
   204  	if use_addWW_g {
   205  		c = y
   206  		for i := range z {
   207  			c, z[i] = addWW_g(x[i], c, 0)
   208  		}
   209  		return
   210  	}
   211  
   212  	c = y
   213  	for i, xi := range x[:len(z)] {
   214  		zi := xi + c
   215  		z[i] = zi
   216  		c = xi &^ zi >> (_W - 1)
   217  	}
   218  	return
   219  }
   220  
   221  func subVW_g(z, x []Word, y Word) (c Word) {
   222  	if use_addWW_g {
   223  		c = y
   224  		for i := range z {
   225  			c, z[i] = subWW_g(x[i], c, 0)
   226  		}
   227  		return
   228  	}
   229  
   230  	c = y
   231  	for i, xi := range x[:len(z)] {
   232  		zi := xi - c
   233  		z[i] = zi
   234  		c = (zi &^ xi) >> (_W - 1)
   235  	}
   236  	return
   237  }
   238  
   239  func shlVU_g(z, x []Word, s uint) (c Word) {
   240  	if n := len(z); n > 0 {
   241  		ŝ := _W - s
   242  		w1 := x[n-1]
   243  		c = w1 >> ŝ
   244  		for i := n - 1; i > 0; i-- {
   245  			w := w1
   246  			w1 = x[i-1]
   247  			z[i] = w<<s | w1>>ŝ
   248  		}
   249  		z[0] = w1 << s
   250  	}
   251  	return
   252  }
   253  
   254  func shrVU_g(z, x []Word, s uint) (c Word) {
   255  	if n := len(z); n > 0 {
   256  		ŝ := _W - s
   257  		w1 := x[0]
   258  		c = w1 << ŝ
   259  		for i := 0; i < n-1; i++ {
   260  			w := w1
   261  			w1 = x[i+1]
   262  			z[i] = w>>s | w1<<ŝ
   263  		}
   264  		z[n-1] = w1 >> s
   265  	}
   266  	return
   267  }
   268  
   269  func mulAddVWW_g(z, x []Word, y, r Word) (c Word) {
   270  	c = r
   271  	for i := range z {
   272  		c, z[i] = mulAddWWW_g(x[i], y, c)
   273  	}
   274  	return
   275  }
   276  
   277  // TODO(gri) Remove use of addWW_g here and then we can remove addWW_g and subWW_g.
   278  func addMulVVW_g(z, x []Word, y Word) (c Word) {
   279  	for i := range z {
   280  		z1, z0 := mulAddWWW_g(x[i], y, z[i])
   281  		c, z[i] = addWW_g(z0, c, 0)
   282  		c += z1
   283  	}
   284  	return
   285  }
   286  
   287  func divWVW_g(z []Word, xn Word, x []Word, y Word) (r Word) {
   288  	r = xn
   289  	for i := len(z) - 1; i >= 0; i-- {
   290  		z[i], r = divWW_g(r, x[i], y)
   291  	}
   292  	return
   293  }