src/pkg/math/big/arith.go - The Go Programming Language

Golang

Source file src/pkg/math/big/arith.go

     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	// This file provides Go implementations of elementary multi-precision
     6	// arithmetic operations on word vectors. Needed for platforms without
     7	// assembly implementations of these routines.
     8	
     9	package big
    10	
    11	// A Word represents a single digit of a multi-precision unsigned integer.
    12	type Word uintptr
    13	
    14	const (
    15		// Compute the size _S of a Word in bytes.
    16		_m    = ^Word(0)
    17		_logS = _m>>8&1 + _m>>16&1 + _m>>32&1
    18		_S    = 1 << _logS
    19	
    20		_W = _S << 3 // word size in bits
    21		_B = 1 << _W // digit base
    22		_M = _B - 1  // digit mask
    23	
    24		_W2 = _W / 2   // half word size in bits
    25		_B2 = 1 << _W2 // half digit base
    26		_M2 = _B2 - 1  // half digit mask
    27	)
    28	
    29	// ----------------------------------------------------------------------------
    30	// Elementary operations on words
    31	//
    32	// These operations are used by the vector operations below.
    33	
    34	// z1<<_W + z0 = x+y+c, with c == 0 or 1
    35	func addWW_g(x, y, c Word) (z1, z0 Word) {
    36		yc := y + c
    37		z0 = x + yc
    38		if z0 < x || yc < y {
    39			z1 = 1
    40		}
    41		return
    42	}
    43	
    44	// z1<<_W + z0 = x-y-c, with c == 0 or 1
    45	func subWW_g(x, y, c Word) (z1, z0 Word) {
    46		yc := y + c
    47		z0 = x - yc
    48		if z0 > x || yc < y {
    49			z1 = 1
    50		}
    51		return
    52	}
    53	
    54	// z1<<_W + z0 = x*y
    55	// Adapted from Warren, Hacker's Delight, p. 132.
    56	func mulWW_g(x, y Word) (z1, z0 Word) {
    57		x0 := x & _M2
    58		x1 := x >> _W2
    59		y0 := y & _M2
    60		y1 := y >> _W2
    61		w0 := x0 * y0
    62		t := x1*y0 + w0>>_W2
    63		w1 := t & _M2
    64		w2 := t >> _W2
    65		w1 += x0 * y1
    66		z1 = x1*y1 + w2 + w1>>_W2
    67		z0 = x * y
    68		return
    69	}
    70	
    71	// z1<<_W + z0 = x*y + c
    72	func mulAddWWW_g(x, y, c Word) (z1, z0 Word) {
    73		z1, zz0 := mulWW(x, y)
    74		if z0 = zz0 + c; z0 < zz0 {
    75			z1++
    76		}
    77		return
    78	}
    79	
    80	// Length of x in bits.
    81	func bitLen_g(x Word) (n int) {
    82		for ; x >= 0x8000; x >>= 16 {
    83			n += 16
    84		}
    85		if x >= 0x80 {
    86			x >>= 8
    87			n += 8
    88		}
    89		if x >= 0x8 {
    90			x >>= 4
    91			n += 4
    92		}
    93		if x >= 0x2 {
    94			x >>= 2
    95			n += 2
    96		}
    97		if x >= 0x1 {
    98			n++
    99		}
   100		return
   101	}
   102	
   103	// log2 computes the integer binary logarithm of x.
   104	// The result is the integer n for which 2^n <= x < 2^(n+1).
   105	// If x == 0, the result is -1.
   106	func log2(x Word) int {
   107		return bitLen(x) - 1
   108	}
   109	
   110	// Number of leading zeros in x.
   111	func leadingZeros(x Word) uint {
   112		return uint(_W - bitLen(x))
   113	}
   114	
   115	// q = (u1<<_W + u0 - r)/y
   116	// Adapted from Warren, Hacker's Delight, p. 152.
   117	func divWW_g(u1, u0, v Word) (q, r Word) {
   118		if u1 >= v {
   119			return 1<<_W - 1, 1<<_W - 1
   120		}
   121	
   122		s := leadingZeros(v)
   123		v <<= s
   124	
   125		vn1 := v >> _W2
   126		vn0 := v & _M2
   127		un32 := u1<<s | u0>>(_W-s)
   128		un10 := u0 << s
   129		un1 := un10 >> _W2
   130		un0 := un10 & _M2
   131		q1 := un32 / vn1
   132		rhat := un32 - q1*vn1
   133	
   134	again1:
   135		if q1 >= _B2 || q1*vn0 > _B2*rhat+un1 {
   136			q1--
   137			rhat += vn1
   138			if rhat < _B2 {
   139				goto again1
   140			}
   141		}
   142	
   143		un21 := un32*_B2 + un1 - q1*v
   144		q0 := un21 / vn1
   145		rhat = un21 - q0*vn1
   146	
   147	again2:
   148		if q0 >= _B2 || q0*vn0 > _B2*rhat+un0 {
   149			q0--
   150			rhat += vn1
   151			if rhat < _B2 {
   152				goto again2
   153			}
   154		}
   155	
   156		return q1*_B2 + q0, (un21*_B2 + un0 - q0*v) >> s
   157	}
   158	
   159	func addVV_g(z, x, y []Word) (c Word) {
   160		for i := range z {
   161			c, z[i] = addWW_g(x[i], y[i], c)
   162		}
   163		return
   164	}
   165	
   166	func subVV_g(z, x, y []Word) (c Word) {
   167		for i := range z {
   168			c, z[i] = subWW_g(x[i], y[i], c)
   169		}
   170		return
   171	}
   172	
   173	func addVW_g(z, x []Word, y Word) (c Word) {
   174		c = y
   175		for i := range z {
   176			c, z[i] = addWW_g(x[i], c, 0)
   177		}
   178		return
   179	}
   180	
   181	func subVW_g(z, x []Word, y Word) (c Word) {
   182		c = y
   183		for i := range z {
   184			c, z[i] = subWW_g(x[i], c, 0)
   185		}
   186		return
   187	}
   188	
   189	func shlVU_g(z, x []Word, s uint) (c Word) {
   190		if n := len(z); n > 0 {
   191			ŝ := _W - s
   192			w1 := x[n-1]
   193			c = w1 >> ŝ
   194			for i := n - 1; i > 0; i-- {
   195				w := w1
   196				w1 = x[i-1]
   197				z[i] = w<<s | w1>>ŝ
   198			}
   199			z[0] = w1 << s
   200		}
   201		return
   202	}
   203	
   204	func shrVU_g(z, x []Word, s uint) (c Word) {
   205		if n := len(z); n > 0 {
   206			ŝ := _W - s
   207			w1 := x[0]
   208			c = w1 << ŝ
   209			for i := 0; i < n-1; i++ {
   210				w := w1
   211				w1 = x[i+1]
   212				z[i] = w>>s | w1<<ŝ
   213			}
   214			z[n-1] = w1 >> s
   215		}
   216		return
   217	}
   218	
   219	func mulAddVWW_g(z, x []Word, y, r Word) (c Word) {
   220		c = r
   221		for i := range z {
   222			c, z[i] = mulAddWWW_g(x[i], y, c)
   223		}
   224		return
   225	}
   226	
   227	func addMulVVW_g(z, x []Word, y Word) (c Word) {
   228		for i := range z {
   229			z1, z0 := mulAddWWW_g(x[i], y, z[i])
   230			c, z[i] = addWW_g(z0, c, 0)
   231			c += z1
   232		}
   233		return
   234	}
   235	
   236	func divWVW_g(z []Word, xn Word, x []Word, y Word) (r Word) {
   237		r = xn
   238		for i := len(z) - 1; i >= 0; i-- {
   239			z[i], r = divWW_g(r, x[i], y)
   240		}
   241		return
   242	}