poly.go (5720B)
1 // Copyright (c) 2016 The mathutil 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 package mathutil // import "modernc.org/mathutil" 6 7 import ( 8 "fmt" 9 "math/big" 10 ) 11 12 func abs(n int) uint64 { 13 if n >= 0 { 14 return uint64(n) 15 } 16 17 return uint64(-n) 18 } 19 20 // QuadPolyDiscriminant returns the discriminant of a quadratic polynomial in 21 // one variable of the form a*x^2+b*x+c with integer coefficients a, b, c, or 22 // an error on overflow. 23 // 24 // ds is the square of the discriminant. If |ds| is a square number, d is set 25 // to sqrt(|ds|), otherwise d is < 0. 26 func QuadPolyDiscriminant(a, b, c int) (ds, d int, _ error) { 27 if 2*BitLenUint64(abs(b)) > IntBits-1 || 28 2+BitLenUint64(abs(a))+BitLenUint64(abs(c)) > IntBits-1 { 29 return 0, 0, fmt.Errorf("overflow") 30 } 31 32 ds = b*b - 4*a*c 33 s := ds 34 if s < 0 { 35 s = -s 36 } 37 d64 := SqrtUint64(uint64(s)) 38 if d64*d64 != uint64(s) { 39 return ds, -1, nil 40 } 41 42 return ds, int(d64), nil 43 } 44 45 // PolyFactor describes an irreducible factor of a polynomial in one variable 46 // with integer coefficients P, Q of the form P*x+Q. 47 type PolyFactor struct { 48 P, Q int 49 } 50 51 // QuadPolyFactors returns the content and the irreducible factors of the 52 // primitive part of a quadratic polynomial in one variable with integer 53 // coefficients a, b, c of the form a*x^2+b*x+c in integers, or an error on 54 // overflow. 55 // 56 // If the factorization in integers does not exists, the return value is (0, 57 // nil, nil). 58 // 59 // See also: 60 // https://en.wikipedia.org/wiki/Factorization_of_polynomials#Primitive_part.E2.80.93content_factorization 61 func QuadPolyFactors(a, b, c int) (content int, primitivePart []PolyFactor, _ error) { 62 content = int(GCDUint64(abs(a), GCDUint64(abs(b), abs(c)))) 63 switch { 64 case content == 0: 65 content = 1 66 case content > 0: 67 if a < 0 || a == 0 && b < 0 { 68 content = -content 69 } 70 } 71 a /= content 72 b /= content 73 c /= content 74 if a == 0 { 75 if b == 0 { 76 return content, []PolyFactor{{0, c}}, nil 77 } 78 79 if b < 0 && c < 0 { 80 b = -b 81 c = -c 82 } 83 if b < 0 { 84 b = -b 85 c = -c 86 } 87 return content, []PolyFactor{{b, c}}, nil 88 } 89 90 ds, d, err := QuadPolyDiscriminant(a, b, c) 91 if err != nil { 92 return 0, nil, err 93 } 94 95 if ds < 0 || d < 0 { 96 return 0, nil, nil 97 } 98 99 x1num := -b + d 100 x1denom := 2 * a 101 gcd := int(GCDUint64(abs(x1num), abs(x1denom))) 102 x1num /= gcd 103 x1denom /= gcd 104 105 x2num := -b - d 106 x2denom := 2 * a 107 gcd = int(GCDUint64(abs(x2num), abs(x2denom))) 108 x2num /= gcd 109 x2denom /= gcd 110 111 return content, []PolyFactor{{x1denom, -x1num}, {x2denom, -x2num}}, nil 112 } 113 114 // QuadPolyDiscriminantBig returns the discriminant of a quadratic polynomial 115 // in one variable of the form a*x^2+b*x+c with integer coefficients a, b, c. 116 // 117 // ds is the square of the discriminant. If |ds| is a square number, d is set 118 // to sqrt(|ds|), otherwise d is nil. 119 func QuadPolyDiscriminantBig(a, b, c *big.Int) (ds, d *big.Int) { 120 ds = big.NewInt(0).Set(b) 121 ds.Mul(ds, b) 122 x := big.NewInt(4) 123 x.Mul(x, a) 124 x.Mul(x, c) 125 ds.Sub(ds, x) 126 127 s := big.NewInt(0).Set(ds) 128 if s.Sign() < 0 { 129 s.Neg(s) 130 } 131 132 if s.Bit(1) != 0 { // s is not a square number 133 return ds, nil 134 } 135 136 d = SqrtBig(s) 137 x.Set(d) 138 x.Mul(x, x) 139 if x.Cmp(s) != 0 { // s is not a square number 140 d = nil 141 } 142 return ds, d 143 } 144 145 // PolyFactorBig describes an irreducible factor of a polynomial in one 146 // variable with integer coefficients P, Q of the form P*x+Q. 147 type PolyFactorBig struct { 148 P, Q *big.Int 149 } 150 151 // QuadPolyFactorsBig returns the content and the irreducible factors of the 152 // primitive part of a quadratic polynomial in one variable with integer 153 // coefficients a, b, c of the form a*x^2+b*x+c in integers. 154 // 155 // If the factorization in integers does not exists, the return value is (nil, 156 // nil). 157 // 158 // See also: 159 // https://en.wikipedia.org/wiki/Factorization_of_polynomials#Primitive_part.E2.80.93content_factorization 160 func QuadPolyFactorsBig(a, b, c *big.Int) (content *big.Int, primitivePart []PolyFactorBig) { 161 content = bigGCD(bigAbs(a), bigGCD(bigAbs(b), bigAbs(c))) 162 switch { 163 case content.Sign() == 0: 164 content.SetInt64(1) 165 case content.Sign() > 0: 166 if a.Sign() < 0 || a.Sign() == 0 && b.Sign() < 0 { 167 content = bigNeg(content) 168 } 169 } 170 a = bigDiv(a, content) 171 b = bigDiv(b, content) 172 c = bigDiv(c, content) 173 174 if a.Sign() == 0 { 175 if b.Sign() == 0 { 176 return content, []PolyFactorBig{{big.NewInt(0), c}} 177 } 178 179 if b.Sign() < 0 && c.Sign() < 0 { 180 b = bigNeg(b) 181 c = bigNeg(c) 182 } 183 if b.Sign() < 0 { 184 b = bigNeg(b) 185 c = bigNeg(c) 186 } 187 return content, []PolyFactorBig{{b, c}} 188 } 189 190 ds, d := QuadPolyDiscriminantBig(a, b, c) 191 if ds.Sign() < 0 || d == nil { 192 return nil, nil 193 } 194 195 x1num := bigAdd(bigNeg(b), d) 196 x1denom := bigMul(_2, a) 197 gcd := bigGCD(bigAbs(x1num), bigAbs(x1denom)) 198 x1num = bigDiv(x1num, gcd) 199 x1denom = bigDiv(x1denom, gcd) 200 201 x2num := bigAdd(bigNeg(b), bigNeg(d)) 202 x2denom := bigMul(_2, a) 203 gcd = bigGCD(bigAbs(x2num), bigAbs(x2denom)) 204 x2num = bigDiv(x2num, gcd) 205 x2denom = bigDiv(x2denom, gcd) 206 207 return content, []PolyFactorBig{{x1denom, bigNeg(x1num)}, {x2denom, bigNeg(x2num)}} 208 } 209 210 func bigAbs(n *big.Int) *big.Int { 211 n = big.NewInt(0).Set(n) 212 if n.Sign() >= 0 { 213 return n 214 } 215 216 return n.Neg(n) 217 } 218 219 func bigDiv(a, b *big.Int) *big.Int { 220 a = big.NewInt(0).Set(a) 221 return a.Div(a, b) 222 } 223 224 func bigGCD(a, b *big.Int) *big.Int { 225 a = big.NewInt(0).Set(a) 226 b = big.NewInt(0).Set(b) 227 for b.Sign() != 0 { 228 c := big.NewInt(0) 229 c.Mod(a, b) 230 a, b = b, c 231 } 232 return a 233 } 234 235 func bigNeg(n *big.Int) *big.Int { 236 n = big.NewInt(0).Set(n) 237 return n.Neg(n) 238 } 239 240 func bigMul(a, b *big.Int) *big.Int { 241 r := big.NewInt(0).Set(a) 242 return r.Mul(r, b) 243 } 244 245 func bigAdd(a, b *big.Int) *big.Int { 246 r := big.NewInt(0).Set(a) 247 return r.Add(r, b) 248 }