[822] | 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 | }
|
---|