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