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  }