github.com/rsc/tmp@v0.0.0-20240517235954-6deaab19748b/bootstrap/internal/gc/big/natconv.go (about) 1 // Do not edit. Bootstrap copy of /Users/rsc/g/go/src/cmd/internal/gc/big/natconv.go 2 3 // Copyright 2015 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 implements nat-to-string conversion functions. 8 9 package big 10 11 import ( 12 "errors" 13 "fmt" 14 "io" 15 "math" 16 "sync" 17 ) 18 19 // MaxBase is the largest number base accepted for string conversions. 20 const MaxBase = 'z' - 'a' + 10 + 1 21 22 // maxPow returns (b**n, n) such that b**n is the largest power b**n <= _M. 23 // For instance maxPow(10) == (1e19, 19) for 19 decimal digits in a 64bit Word. 24 // In other words, at most n digits in base b fit into a Word. 25 // TODO(gri) replace this with a table, generated at build time. 26 func maxPow(b Word) (p Word, n int) { 27 p, n = b, 1 // assuming b <= _M 28 for max := _M / b; p <= max; { 29 // p == b**n && p <= max 30 p *= b 31 n++ 32 } 33 // p == b**n && p <= _M 34 return 35 } 36 37 // pow returns x**n for n > 0, and 1 otherwise. 38 func pow(x Word, n int) (p Word) { 39 // n == sum of bi * 2**i, for 0 <= i < imax, and bi is 0 or 1 40 // thus x**n == product of x**(2**i) for all i where bi == 1 41 // (Russian Peasant Method for exponentiation) 42 p = 1 43 for n > 0 { 44 if n&1 != 0 { 45 p *= x 46 } 47 x *= x 48 n >>= 1 49 } 50 return 51 } 52 53 // scan scans the number corresponding to the longest possible prefix 54 // from r representing an unsigned number in a given conversion base. 55 // It returns the corresponding natural number res, the actual base b, 56 // a digit count, and a read or syntax error err, if any. 57 // 58 // number = [ prefix ] mantissa . 59 // prefix = "0" [ "x" | "X" | "b" | "B" ] . 60 // mantissa = digits | digits "." [ digits ] | "." digits . 61 // digits = digit { digit } . 62 // digit = "0" ... "9" | "a" ... "z" | "A" ... "Z" . 63 // 64 // Unless fracOk is set, the base argument must be 0 or a value between 65 // 2 and MaxBase. If fracOk is set, the base argument must be one of 66 // 0, 2, 10, or 16. Providing an invalid base argument leads to a run- 67 // time panic. 68 // 69 // For base 0, the number prefix determines the actual base: A prefix of 70 // ``0x'' or ``0X'' selects base 16; if fracOk is not set, the ``0'' prefix 71 // selects base 8, and a ``0b'' or ``0B'' prefix selects base 2. Otherwise 72 // the selected base is 10 and no prefix is accepted. 73 // 74 // If fracOk is set, an octal prefix is ignored (a leading ``0'' simply 75 // stands for a zero digit), and a period followed by a fractional part 76 // is permitted. The result value is computed as if there were no period 77 // present; and the count value is used to determine the fractional part. 78 // 79 // A result digit count > 0 corresponds to the number of (non-prefix) digits 80 // parsed. A digit count <= 0 indicates the presence of a period (if fracOk 81 // is set, only), and -count is the number of fractional digits found. 82 // In this case, the actual value of the scanned number is res * b**count. 83 // 84 func (z nat) scan(r io.ByteScanner, base int, fracOk bool) (res nat, b, count int, err error) { 85 // reject illegal bases 86 baseOk := base == 0 || 87 !fracOk && 2 <= base && base <= MaxBase || 88 fracOk && (base == 2 || base == 10 || base == 16) 89 if !baseOk { 90 panic(fmt.Sprintf("illegal number base %d", base)) 91 } 92 93 // one char look-ahead 94 ch, err := r.ReadByte() 95 if err != nil { 96 return 97 } 98 99 // determine actual base 100 b = base 101 if base == 0 { 102 // actual base is 10 unless there's a base prefix 103 b = 10 104 if ch == '0' { 105 count = 1 106 switch ch, err = r.ReadByte(); err { 107 case nil: 108 // possibly one of 0x, 0X, 0b, 0B 109 if !fracOk { 110 b = 8 111 } 112 switch ch { 113 case 'x', 'X': 114 b = 16 115 case 'b', 'B': 116 b = 2 117 } 118 switch b { 119 case 16, 2: 120 count = 0 // prefix is not counted 121 if ch, err = r.ReadByte(); err != nil { 122 // io.EOF is also an error in this case 123 return 124 } 125 case 8: 126 count = 0 // prefix is not counted 127 } 128 case io.EOF: 129 // input is "0" 130 res = z[:0] 131 err = nil 132 return 133 default: 134 // read error 135 return 136 } 137 } 138 } 139 140 // convert string 141 // Algorithm: Collect digits in groups of at most n digits in di 142 // and then use mulAddWW for every such group to add them to the 143 // result. 144 z = z[:0] 145 b1 := Word(b) 146 bn, n := maxPow(b1) // at most n digits in base b1 fit into Word 147 di := Word(0) // 0 <= di < b1**i < bn 148 i := 0 // 0 <= i < n 149 dp := -1 // position of decimal point 150 for { 151 if fracOk && ch == '.' { 152 fracOk = false 153 dp = count 154 // advance 155 if ch, err = r.ReadByte(); err != nil { 156 if err == io.EOF { 157 err = nil 158 break 159 } 160 return 161 } 162 } 163 164 // convert rune into digit value d1 165 var d1 Word 166 switch { 167 case '0' <= ch && ch <= '9': 168 d1 = Word(ch - '0') 169 case 'a' <= ch && ch <= 'z': 170 d1 = Word(ch - 'a' + 10) 171 case 'A' <= ch && ch <= 'Z': 172 d1 = Word(ch - 'A' + 10) 173 default: 174 d1 = MaxBase + 1 175 } 176 if d1 >= b1 { 177 r.UnreadByte() // ch does not belong to number anymore 178 break 179 } 180 count++ 181 182 // collect d1 in di 183 di = di*b1 + d1 184 i++ 185 186 // if di is "full", add it to the result 187 if i == n { 188 z = z.mulAddWW(z, bn, di) 189 di = 0 190 i = 0 191 } 192 193 // advance 194 if ch, err = r.ReadByte(); err != nil { 195 if err == io.EOF { 196 err = nil 197 break 198 } 199 return 200 } 201 } 202 203 if count == 0 { 204 // no digits found 205 switch { 206 case base == 0 && b == 8: 207 // there was only the octal prefix 0 (possibly followed by digits > 7); 208 // count as one digit and return base 10, not 8 209 count = 1 210 b = 10 211 case base != 0 || b != 8: 212 // there was neither a mantissa digit nor the octal prefix 0 213 err = errors.New("syntax error scanning number") 214 } 215 return 216 } 217 // count > 0 218 219 // add remaining digits to result 220 if i > 0 { 221 z = z.mulAddWW(z, pow(b1, i), di) 222 } 223 res = z.norm() 224 225 // adjust for fraction, if any 226 if dp >= 0 { 227 // 0 <= dp <= count > 0 228 count = dp - count 229 } 230 231 return 232 } 233 234 // Character sets for string conversion. 235 const ( 236 lowercaseDigits = "0123456789abcdefghijklmnopqrstuvwxyz" 237 uppercaseDigits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" 238 ) 239 240 // decimalString returns a decimal representation of x. 241 // It calls x.string with the charset "0123456789". 242 func (x nat) decimalString() string { 243 return x.string(lowercaseDigits[:10]) 244 } 245 246 // hexString returns a hexadecimal representation of x. 247 // It calls x.string with the charset "0123456789abcdef". 248 func (x nat) hexString() string { 249 return x.string(lowercaseDigits[:16]) 250 } 251 252 // string converts x to a string using digits from a charset; a digit with 253 // value d is represented by charset[d]. The conversion base is determined 254 // by len(charset), which must be >= 2 and <= 256. 255 func (x nat) string(charset string) string { 256 b := Word(len(charset)) 257 258 // special cases 259 switch { 260 case b < 2 || b > 256: 261 panic("invalid character set length") 262 case len(x) == 0: 263 return string(charset[0]) 264 } 265 266 // allocate buffer for conversion 267 i := int(float64(x.bitLen())/math.Log2(float64(b))) + 1 // off by one at most 268 s := make([]byte, i) 269 270 // convert power of two and non power of two bases separately 271 if b == b&-b { 272 // shift is base-b digit size in bits 273 shift := trailingZeroBits(b) // shift > 0 because b >= 2 274 mask := Word(1)<<shift - 1 275 w := x[0] 276 nbits := uint(_W) // number of unprocessed bits in w 277 278 // convert less-significant words 279 for k := 1; k < len(x); k++ { 280 // convert full digits 281 for nbits >= shift { 282 i-- 283 s[i] = charset[w&mask] 284 w >>= shift 285 nbits -= shift 286 } 287 288 // convert any partial leading digit and advance to next word 289 if nbits == 0 { 290 // no partial digit remaining, just advance 291 w = x[k] 292 nbits = _W 293 } else { 294 // partial digit in current (k-1) and next (k) word 295 w |= x[k] << nbits 296 i-- 297 s[i] = charset[w&mask] 298 299 // advance 300 w = x[k] >> (shift - nbits) 301 nbits = _W - (shift - nbits) 302 } 303 } 304 305 // convert digits of most-significant word (omit leading zeros) 306 for nbits >= 0 && w != 0 { 307 i-- 308 s[i] = charset[w&mask] 309 w >>= shift 310 nbits -= shift 311 } 312 313 } else { 314 bb, ndigits := maxPow(Word(b)) 315 316 // construct table of successive squares of bb*leafSize to use in subdivisions 317 // result (table != nil) <=> (len(x) > leafSize > 0) 318 table := divisors(len(x), b, ndigits, bb) 319 320 // preserve x, create local copy for use by convertWords 321 q := nat(nil).set(x) 322 323 // convert q to string s in base b 324 q.convertWords(s, charset, b, ndigits, bb, table) 325 326 // strip leading zeros 327 // (x != 0; thus s must contain at least one non-zero digit 328 // and the loop will terminate) 329 i = 0 330 for zero := charset[0]; s[i] == zero; { 331 i++ 332 } 333 } 334 335 return string(s[i:]) 336 } 337 338 // Convert words of q to base b digits in s. If q is large, it is recursively "split in half" 339 // by nat/nat division using tabulated divisors. Otherwise, it is converted iteratively using 340 // repeated nat/Word division. 341 // 342 // The iterative method processes n Words by n divW() calls, each of which visits every Word in the 343 // incrementally shortened q for a total of n + (n-1) + (n-2) ... + 2 + 1, or n(n+1)/2 divW()'s. 344 // Recursive conversion divides q by its approximate square root, yielding two parts, each half 345 // the size of q. Using the iterative method on both halves means 2 * (n/2)(n/2 + 1)/2 divW()'s 346 // plus the expensive long div(). Asymptotically, the ratio is favorable at 1/2 the divW()'s, and 347 // is made better by splitting the subblocks recursively. Best is to split blocks until one more 348 // split would take longer (because of the nat/nat div()) than the twice as many divW()'s of the 349 // iterative approach. This threshold is represented by leafSize. Benchmarking of leafSize in the 350 // range 2..64 shows that values of 8 and 16 work well, with a 4x speedup at medium lengths and 351 // ~30x for 20000 digits. Use nat_test.go's BenchmarkLeafSize tests to optimize leafSize for 352 // specific hardware. 353 // 354 func (q nat) convertWords(s []byte, charset string, b Word, ndigits int, bb Word, table []divisor) { 355 // split larger blocks recursively 356 if table != nil { 357 // len(q) > leafSize > 0 358 var r nat 359 index := len(table) - 1 360 for len(q) > leafSize { 361 // find divisor close to sqrt(q) if possible, but in any case < q 362 maxLength := q.bitLen() // ~= log2 q, or at of least largest possible q of this bit length 363 minLength := maxLength >> 1 // ~= log2 sqrt(q) 364 for index > 0 && table[index-1].nbits > minLength { 365 index-- // desired 366 } 367 if table[index].nbits >= maxLength && table[index].bbb.cmp(q) >= 0 { 368 index-- 369 if index < 0 { 370 panic("internal inconsistency") 371 } 372 } 373 374 // split q into the two digit number (q'*bbb + r) to form independent subblocks 375 q, r = q.div(r, q, table[index].bbb) 376 377 // convert subblocks and collect results in s[:h] and s[h:] 378 h := len(s) - table[index].ndigits 379 r.convertWords(s[h:], charset, b, ndigits, bb, table[0:index]) 380 s = s[:h] // == q.convertWords(s, charset, b, ndigits, bb, table[0:index+1]) 381 } 382 } 383 384 // having split any large blocks now process the remaining (small) block iteratively 385 i := len(s) 386 var r Word 387 if b == 10 { 388 // hard-coding for 10 here speeds this up by 1.25x (allows for / and % by constants) 389 for len(q) > 0 { 390 // extract least significant, base bb "digit" 391 q, r = q.divW(q, bb) 392 for j := 0; j < ndigits && i > 0; j++ { 393 i-- 394 // avoid % computation since r%10 == r - int(r/10)*10; 395 // this appears to be faster for BenchmarkString10000Base10 396 // and smaller strings (but a bit slower for larger ones) 397 t := r / 10 398 s[i] = charset[r-t<<3-t-t] // TODO(gri) replace w/ t*10 once compiler produces better code 399 r = t 400 } 401 } 402 } else { 403 for len(q) > 0 { 404 // extract least significant, base bb "digit" 405 q, r = q.divW(q, bb) 406 for j := 0; j < ndigits && i > 0; j++ { 407 i-- 408 s[i] = charset[r%b] 409 r /= b 410 } 411 } 412 } 413 414 // prepend high-order zeroes 415 zero := charset[0] 416 for i > 0 { // while need more leading zeroes 417 i-- 418 s[i] = zero 419 } 420 } 421 422 // Split blocks greater than leafSize Words (or set to 0 to disable recursive conversion) 423 // Benchmark and configure leafSize using: go test -bench="Leaf" 424 // 8 and 16 effective on 3.0 GHz Xeon "Clovertown" CPU (128 byte cache lines) 425 // 8 and 16 effective on 2.66 GHz Core 2 Duo "Penryn" CPU 426 var leafSize int = 8 // number of Word-size binary values treat as a monolithic block 427 428 type divisor struct { 429 bbb nat // divisor 430 nbits int // bit length of divisor (discounting leading zeroes) ~= log2(bbb) 431 ndigits int // digit length of divisor in terms of output base digits 432 } 433 434 var cacheBase10 struct { 435 sync.Mutex 436 table [64]divisor // cached divisors for base 10 437 } 438 439 // expWW computes x**y 440 func (z nat) expWW(x, y Word) nat { 441 return z.expNN(nat(nil).setWord(x), nat(nil).setWord(y), nil) 442 } 443 444 // construct table of powers of bb*leafSize to use in subdivisions 445 func divisors(m int, b Word, ndigits int, bb Word) []divisor { 446 // only compute table when recursive conversion is enabled and x is large 447 if leafSize == 0 || m <= leafSize { 448 return nil 449 } 450 451 // determine k where (bb**leafSize)**(2**k) >= sqrt(x) 452 k := 1 453 for words := leafSize; words < m>>1 && k < len(cacheBase10.table); words <<= 1 { 454 k++ 455 } 456 457 // reuse and extend existing table of divisors or create new table as appropriate 458 var table []divisor // for b == 10, table overlaps with cacheBase10.table 459 if b == 10 { 460 cacheBase10.Lock() 461 table = cacheBase10.table[0:k] // reuse old table for this conversion 462 } else { 463 table = make([]divisor, k) // create new table for this conversion 464 } 465 466 // extend table 467 if table[k-1].ndigits == 0 { 468 // add new entries as needed 469 var larger nat 470 for i := 0; i < k; i++ { 471 if table[i].ndigits == 0 { 472 if i == 0 { 473 table[0].bbb = nat(nil).expWW(bb, Word(leafSize)) 474 table[0].ndigits = ndigits * leafSize 475 } else { 476 table[i].bbb = nat(nil).mul(table[i-1].bbb, table[i-1].bbb) 477 table[i].ndigits = 2 * table[i-1].ndigits 478 } 479 480 // optimization: exploit aggregated extra bits in macro blocks 481 larger = nat(nil).set(table[i].bbb) 482 for mulAddVWW(larger, larger, b, 0) == 0 { 483 table[i].bbb = table[i].bbb.set(larger) 484 table[i].ndigits++ 485 } 486 487 table[i].nbits = table[i].bbb.bitLen() 488 } 489 } 490 } 491 492 if b == 10 { 493 cacheBase10.Unlock() 494 } 495 496 return table 497 }