github.com/remyoudompheng/bigfft@v0.0.0-20230129092748-24d4a6f8daec/scan.go (about)

     1  package bigfft
     2  
     3  import (
     4  	"math/big"
     5  )
     6  
     7  // FromDecimalString converts the base 10 string
     8  // representation of a natural (non-negative) number
     9  // into a *big.Int.
    10  // Its asymptotic complexity is less than quadratic.
    11  func FromDecimalString(s string) *big.Int {
    12  	var sc scanner
    13  	z := new(big.Int)
    14  	sc.scan(z, s)
    15  	return z
    16  }
    17  
    18  type scanner struct {
    19  	// powers[i] is 10^(2^i * quadraticScanThreshold).
    20  	powers []*big.Int
    21  }
    22  
    23  func (s *scanner) chunkSize(size int) (int, *big.Int) {
    24  	if size <= quadraticScanThreshold {
    25  		panic("size < quadraticScanThreshold")
    26  	}
    27  	pow := uint(0)
    28  	for n := size; n > quadraticScanThreshold; n /= 2 {
    29  		pow++
    30  	}
    31  	// threshold * 2^(pow-1) <= size < threshold * 2^pow
    32  	return quadraticScanThreshold << (pow - 1), s.power(pow - 1)
    33  }
    34  
    35  func (s *scanner) power(k uint) *big.Int {
    36  	for i := len(s.powers); i <= int(k); i++ {
    37  		z := new(big.Int)
    38  		if i == 0 {
    39  			if quadraticScanThreshold%14 != 0 {
    40  				panic("quadraticScanThreshold % 14 != 0")
    41  			}
    42  			z.Exp(big.NewInt(1e14), big.NewInt(quadraticScanThreshold/14), nil)
    43  		} else {
    44  			z.Mul(s.powers[i-1], s.powers[i-1])
    45  		}
    46  		s.powers = append(s.powers, z)
    47  	}
    48  	return s.powers[k]
    49  }
    50  
    51  func (s *scanner) scan(z *big.Int, str string) {
    52  	if len(str) <= quadraticScanThreshold {
    53  		z.SetString(str, 10)
    54  		return
    55  	}
    56  	sz, pow := s.chunkSize(len(str))
    57  	// Scan the left half.
    58  	s.scan(z, str[:len(str)-sz])
    59  	// FIXME: reuse temporaries.
    60  	left := Mul(z, pow)
    61  	// Scan the right half
    62  	s.scan(z, str[len(str)-sz:])
    63  	z.Add(z, left)
    64  }
    65  
    66  // quadraticScanThreshold is the number of digits
    67  // below which big.Int.SetString is more efficient
    68  // than subquadratic algorithms.
    69  // 1232 digits fit in 4096 bits.
    70  const quadraticScanThreshold = 1232