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