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