...

Source file src/math/big/natconv.go

Documentation: math/big

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

View as plain text