mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			306 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			306 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			Go
		
	
	
	
// Copyright 2009 The Go Authors. All rights reserved.
 | 
						|
// Use of this source code is governed by a BSD-style
 | 
						|
// license that can be found in the LICENSE file.
 | 
						|
 | 
						|
// This file provides Go implementations of elementary multi-precision
 | 
						|
// arithmetic operations on word vectors. Needed for platforms without
 | 
						|
// assembly implementations of these routines.
 | 
						|
 | 
						|
package big
 | 
						|
 | 
						|
// A Word represents a single digit of a multi-precision unsigned integer.
 | 
						|
type Word uintptr
 | 
						|
 | 
						|
const (
 | 
						|
	// Compute the size _S of a Word in bytes.
 | 
						|
	_m    = ^Word(0)
 | 
						|
	_logS = _m>>8&1 + _m>>16&1 + _m>>32&1
 | 
						|
	_S    = 1 << _logS
 | 
						|
 | 
						|
	_W = _S << 3 // word size in bits
 | 
						|
	_B = 1 << _W // digit base
 | 
						|
	_M = _B - 1  // digit mask
 | 
						|
 | 
						|
	_W2 = _W / 2   // half word size in bits
 | 
						|
	_B2 = 1 << _W2 // half digit base
 | 
						|
	_M2 = _B2 - 1  // half digit mask
 | 
						|
)
 | 
						|
 | 
						|
// ----------------------------------------------------------------------------
 | 
						|
// Elementary operations on words
 | 
						|
//
 | 
						|
// These operations are used by the vector operations below.
 | 
						|
 | 
						|
// z1<<_W + z0 = x+y+c, with c == 0 or 1
 | 
						|
func addWW_g(x, y, c Word) (z1, z0 Word) {
 | 
						|
	yc := y + c
 | 
						|
	z0 = x + yc
 | 
						|
	if z0 < x || yc < y {
 | 
						|
		z1 = 1
 | 
						|
	}
 | 
						|
	return
 | 
						|
}
 | 
						|
 | 
						|
// z1<<_W + z0 = x-y-c, with c == 0 or 1
 | 
						|
func subWW_g(x, y, c Word) (z1, z0 Word) {
 | 
						|
	yc := y + c
 | 
						|
	z0 = x - yc
 | 
						|
	if z0 > x || yc < y {
 | 
						|
		z1 = 1
 | 
						|
	}
 | 
						|
	return
 | 
						|
}
 | 
						|
 | 
						|
// z1<<_W + z0 = x*y
 | 
						|
// Adapted from Warren, Hacker's Delight, p. 132.
 | 
						|
func mulWW_g(x, y Word) (z1, z0 Word) {
 | 
						|
	x0 := x & _M2
 | 
						|
	x1 := x >> _W2
 | 
						|
	y0 := y & _M2
 | 
						|
	y1 := y >> _W2
 | 
						|
	w0 := x0 * y0
 | 
						|
	t := x1*y0 + w0>>_W2
 | 
						|
	w1 := t & _M2
 | 
						|
	w2 := t >> _W2
 | 
						|
	w1 += x0 * y1
 | 
						|
	z1 = x1*y1 + w2 + w1>>_W2
 | 
						|
	z0 = x * y
 | 
						|
	return
 | 
						|
}
 | 
						|
 | 
						|
// z1<<_W + z0 = x*y + c
 | 
						|
func mulAddWWW_g(x, y, c Word) (z1, z0 Word) {
 | 
						|
	z1, zz0 := mulWW_g(x, y)
 | 
						|
	if z0 = zz0 + c; z0 < zz0 {
 | 
						|
		z1++
 | 
						|
	}
 | 
						|
	return
 | 
						|
}
 | 
						|
 | 
						|
// Length of x in bits.
 | 
						|
func bitLen_g(x Word) (n int) {
 | 
						|
	for ; x >= 0x8000; x >>= 16 {
 | 
						|
		n += 16
 | 
						|
	}
 | 
						|
	if x >= 0x80 {
 | 
						|
		x >>= 8
 | 
						|
		n += 8
 | 
						|
	}
 | 
						|
	if x >= 0x8 {
 | 
						|
		x >>= 4
 | 
						|
		n += 4
 | 
						|
	}
 | 
						|
	if x >= 0x2 {
 | 
						|
		x >>= 2
 | 
						|
		n += 2
 | 
						|
	}
 | 
						|
	if x >= 0x1 {
 | 
						|
		n++
 | 
						|
	}
 | 
						|
	return
 | 
						|
}
 | 
						|
 | 
						|
// log2 computes the integer binary logarithm of x.
 | 
						|
// The result is the integer n for which 2^n <= x < 2^(n+1).
 | 
						|
// If x == 0, the result is -1.
 | 
						|
func log2(x Word) int {
 | 
						|
	return bitLen(x) - 1
 | 
						|
}
 | 
						|
 | 
						|
// nlz returns the number of leading zeros in x.
 | 
						|
func nlz(x Word) uint {
 | 
						|
	return uint(_W - bitLen(x))
 | 
						|
}
 | 
						|
 | 
						|
// nlz64 returns the number of leading zeros in x.
 | 
						|
func nlz64(x uint64) uint {
 | 
						|
	switch _W {
 | 
						|
	case 32:
 | 
						|
		w := x >> 32
 | 
						|
		if w == 0 {
 | 
						|
			return 32 + nlz(Word(x))
 | 
						|
		}
 | 
						|
		return nlz(Word(w))
 | 
						|
	case 64:
 | 
						|
		return nlz(Word(x))
 | 
						|
	}
 | 
						|
	panic("unreachable")
 | 
						|
}
 | 
						|
 | 
						|
// q = (u1<<_W + u0 - r)/y
 | 
						|
// Adapted from Warren, Hacker's Delight, p. 152.
 | 
						|
func divWW_g(u1, u0, v Word) (q, r Word) {
 | 
						|
	if u1 >= v {
 | 
						|
		return 1<<_W - 1, 1<<_W - 1
 | 
						|
	}
 | 
						|
 | 
						|
	s := nlz(v)
 | 
						|
	v <<= s
 | 
						|
 | 
						|
	vn1 := v >> _W2
 | 
						|
	vn0 := v & _M2
 | 
						|
	un32 := u1<<s | u0>>(_W-s)
 | 
						|
	un10 := u0 << s
 | 
						|
	un1 := un10 >> _W2
 | 
						|
	un0 := un10 & _M2
 | 
						|
	q1 := un32 / vn1
 | 
						|
	rhat := un32 - q1*vn1
 | 
						|
 | 
						|
	for q1 >= _B2 || q1*vn0 > _B2*rhat+un1 {
 | 
						|
		q1--
 | 
						|
		rhat += vn1
 | 
						|
		if rhat >= _B2 {
 | 
						|
			break
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	un21 := un32*_B2 + un1 - q1*v
 | 
						|
	q0 := un21 / vn1
 | 
						|
	rhat = un21 - q0*vn1
 | 
						|
 | 
						|
	for q0 >= _B2 || q0*vn0 > _B2*rhat+un0 {
 | 
						|
		q0--
 | 
						|
		rhat += vn1
 | 
						|
		if rhat >= _B2 {
 | 
						|
			break
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return q1*_B2 + q0, (un21*_B2 + un0 - q0*v) >> s
 | 
						|
}
 | 
						|
 | 
						|
// Keep for performance debugging.
 | 
						|
// Using addWW_g is likely slower.
 | 
						|
const use_addWW_g = false
 | 
						|
 | 
						|
// The resulting carry c is either 0 or 1.
 | 
						|
func addVV_g(z, x, y []Word) (c Word) {
 | 
						|
	if use_addWW_g {
 | 
						|
		for i := range z {
 | 
						|
			c, z[i] = addWW_g(x[i], y[i], c)
 | 
						|
		}
 | 
						|
		return
 | 
						|
	}
 | 
						|
 | 
						|
	for i, xi := range x[:len(z)] {
 | 
						|
		yi := y[i]
 | 
						|
		zi := xi + yi + c
 | 
						|
		z[i] = zi
 | 
						|
		// see "Hacker's Delight", section 2-12 (overflow detection)
 | 
						|
		c = (xi&yi | (xi|yi)&^zi) >> (_W - 1)
 | 
						|
	}
 | 
						|
	return
 | 
						|
}
 | 
						|
 | 
						|
// The resulting carry c is either 0 or 1.
 | 
						|
func subVV_g(z, x, y []Word) (c Word) {
 | 
						|
	if use_addWW_g {
 | 
						|
		for i := range z {
 | 
						|
			c, z[i] = subWW_g(x[i], y[i], c)
 | 
						|
		}
 | 
						|
		return
 | 
						|
	}
 | 
						|
 | 
						|
	for i, xi := range x[:len(z)] {
 | 
						|
		yi := y[i]
 | 
						|
		zi := xi - yi - c
 | 
						|
		z[i] = zi
 | 
						|
		// see "Hacker's Delight", section 2-12 (overflow detection)
 | 
						|
		c = (yi&^xi | (yi|^xi)&zi) >> (_W - 1)
 | 
						|
	}
 | 
						|
	return
 | 
						|
}
 | 
						|
 | 
						|
// The resulting carry c is either 0 or 1.
 | 
						|
func addVW_g(z, x []Word, y Word) (c Word) {
 | 
						|
	if use_addWW_g {
 | 
						|
		c = y
 | 
						|
		for i := range z {
 | 
						|
			c, z[i] = addWW_g(x[i], c, 0)
 | 
						|
		}
 | 
						|
		return
 | 
						|
	}
 | 
						|
 | 
						|
	c = y
 | 
						|
	for i, xi := range x[:len(z)] {
 | 
						|
		zi := xi + c
 | 
						|
		z[i] = zi
 | 
						|
		c = xi &^ zi >> (_W - 1)
 | 
						|
	}
 | 
						|
	return
 | 
						|
}
 | 
						|
 | 
						|
func subVW_g(z, x []Word, y Word) (c Word) {
 | 
						|
	if use_addWW_g {
 | 
						|
		c = y
 | 
						|
		for i := range z {
 | 
						|
			c, z[i] = subWW_g(x[i], c, 0)
 | 
						|
		}
 | 
						|
		return
 | 
						|
	}
 | 
						|
 | 
						|
	c = y
 | 
						|
	for i, xi := range x[:len(z)] {
 | 
						|
		zi := xi - c
 | 
						|
		z[i] = zi
 | 
						|
		c = (zi &^ xi) >> (_W - 1)
 | 
						|
	}
 | 
						|
	return
 | 
						|
}
 | 
						|
 | 
						|
func shlVU_g(z, x []Word, s uint) (c Word) {
 | 
						|
	if n := len(z); n > 0 {
 | 
						|
		ŝ := _W - s
 | 
						|
		w1 := x[n-1]
 | 
						|
		c = w1 >> ŝ
 | 
						|
		for i := n - 1; i > 0; i-- {
 | 
						|
			w := w1
 | 
						|
			w1 = x[i-1]
 | 
						|
			z[i] = w<<s | w1>>ŝ
 | 
						|
		}
 | 
						|
		z[0] = w1 << s
 | 
						|
	}
 | 
						|
	return
 | 
						|
}
 | 
						|
 | 
						|
func shrVU_g(z, x []Word, s uint) (c Word) {
 | 
						|
	if n := len(z); n > 0 {
 | 
						|
		ŝ := _W - s
 | 
						|
		w1 := x[0]
 | 
						|
		c = w1 << ŝ
 | 
						|
		for i := 0; i < n-1; i++ {
 | 
						|
			w := w1
 | 
						|
			w1 = x[i+1]
 | 
						|
			z[i] = w>>s | w1<<ŝ
 | 
						|
		}
 | 
						|
		z[n-1] = w1 >> s
 | 
						|
	}
 | 
						|
	return
 | 
						|
}
 | 
						|
 | 
						|
func mulAddVWW_g(z, x []Word, y, r Word) (c Word) {
 | 
						|
	c = r
 | 
						|
	for i := range z {
 | 
						|
		c, z[i] = mulAddWWW_g(x[i], y, c)
 | 
						|
	}
 | 
						|
	return
 | 
						|
}
 | 
						|
 | 
						|
// TODO(gri) Remove use of addWW_g here and then we can remove addWW_g and subWW_g.
 | 
						|
func addMulVVW_g(z, x []Word, y Word) (c Word) {
 | 
						|
	for i := range z {
 | 
						|
		z1, z0 := mulAddWWW_g(x[i], y, z[i])
 | 
						|
		c, z[i] = addWW_g(z0, c, 0)
 | 
						|
		c += z1
 | 
						|
	}
 | 
						|
	return
 | 
						|
}
 | 
						|
 | 
						|
func divWVW_g(z []Word, xn Word, x []Word, y Word) (r Word) {
 | 
						|
	r = xn
 | 
						|
	for i := len(z) - 1; i >= 0; i-- {
 | 
						|
		z[i], r = divWW_g(r, x[i], y)
 | 
						|
	}
 | 
						|
	return
 | 
						|
}
 |