github.com/filecoin-project/specs-actors/v4@v4.0.2/actors/util/math/ln.go (about) 1 package math 2 3 import ( 4 gbig "math/big" 5 6 "github.com/filecoin-project/go-state-types/big" 7 ) 8 9 var ( 10 // Coefficients in Q.128 format 11 lnNumCoef []*gbig.Int 12 lnDenomCoef []*gbig.Int 13 ln2 big.Int 14 ) 15 16 func init() { 17 // ln approximation coefficients 18 // parameters are in integer format, 19 // coefficients are *2^-128 of that 20 // so we can just load them if we treat them as Q.128 21 num := []string{ 22 "261417938209272870992496419296200268025", 23 "7266615505142943436908456158054846846897", 24 "32458783941900493142649393804518050491988", 25 "17078670566130897220338060387082146864806", 26 "-35150353308172866634071793531642638290419", 27 "-20351202052858059355702509232125230498980", 28 "-1563932590352680681114104005183375350999", 29 } 30 lnNumCoef = Parse(num) 31 32 denom := []string{ 33 "49928077726659937662124949977867279384", 34 "2508163877009111928787629628566491583994", 35 "21757751789594546643737445330202599887121", 36 "53400635271583923415775576342898617051826", 37 "41248834748603606604000911015235164348839", 38 "9015227820322455780436733526367238305537", 39 "340282366920938463463374607431768211456", 40 } 41 lnDenomCoef = Parse(denom) 42 43 constStrs := []string{ 44 "235865763225513294137944142764154484399", // ln(2) 45 } 46 constBigs := Parse(constStrs) 47 ln2 = big.NewFromGo(constBigs[0]) 48 } 49 50 // The natural log of Q.128 x. 51 func Ln(z big.Int) big.Int { 52 // bitlen - 1 - precision 53 k := int64(z.BitLen()) - 1 - Precision128 // Q.0 54 x := big.Zero() // nolint:ineffassign 55 56 if k > 0 { 57 x = big.Rsh(z, uint(k)) // Q.128 58 } else { 59 x = big.Lsh(z, uint(-k)) // Q.128 60 } 61 62 // ln(z) = ln(x * 2^k) = ln(x) + k * ln2 63 lnz := big.Mul(big.NewInt(k), ln2) // Q.0 * Q.128 => Q.128 64 return big.Sum(lnz, lnBetweenOneAndTwo(x)) // Q.128 65 } 66 67 // The natural log of x, specified in Q.128 format 68 // Should only use with 1 <= x <= 2 69 // Output is in Q.128 format. 70 func lnBetweenOneAndTwo(x big.Int) big.Int { 71 // ln is approximated by rational function 72 // polynomials of the rational function are evaluated using Horner's method 73 num := Polyval(lnNumCoef, x.Int) // Q.128 74 denom := Polyval(lnDenomCoef, x.Int) // Q.128 75 76 num = num.Lsh(num, Precision128) // Q.128 => Q.256 77 return big.NewFromGo(num.Div(num, denom)) // Q.256 / Q.128 => Q.128 78 }