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 }