diff options
Diffstat (limited to 'vendor/modernc.org/mathutil/poly.go')
-rw-r--r-- | vendor/modernc.org/mathutil/poly.go | 248 |
1 files changed, 248 insertions, 0 deletions
diff --git a/vendor/modernc.org/mathutil/poly.go b/vendor/modernc.org/mathutil/poly.go new file mode 100644 index 00000000..c15e696c --- /dev/null +++ b/vendor/modernc.org/mathutil/poly.go @@ -0,0 +1,248 @@ +// Copyright (c) 2016 The mathutil Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package mathutil // import "modernc.org/mathutil" + +import ( + "fmt" + "math/big" +) + +func abs(n int) uint64 { + if n >= 0 { + return uint64(n) + } + + return uint64(-n) +} + +// QuadPolyDiscriminant returns the discriminant of a quadratic polynomial in +// one variable of the form a*x^2+b*x+c with integer coefficients a, b, c, or +// an error on overflow. +// +// ds is the square of the discriminant. If |ds| is a square number, d is set +// to sqrt(|ds|), otherwise d is < 0. +func QuadPolyDiscriminant(a, b, c int) (ds, d int, _ error) { + if 2*BitLenUint64(abs(b)) > IntBits-1 || + 2+BitLenUint64(abs(a))+BitLenUint64(abs(c)) > IntBits-1 { + return 0, 0, fmt.Errorf("overflow") + } + + ds = b*b - 4*a*c + s := ds + if s < 0 { + s = -s + } + d64 := SqrtUint64(uint64(s)) + if d64*d64 != uint64(s) { + return ds, -1, nil + } + + return ds, int(d64), nil +} + +// PolyFactor describes an irreducible factor of a polynomial in one variable +// with integer coefficients P, Q of the form P*x+Q. +type PolyFactor struct { + P, Q int +} + +// QuadPolyFactors returns the content and the irreducible factors of the +// primitive part of a quadratic polynomial in one variable with integer +// coefficients a, b, c of the form a*x^2+b*x+c in integers, or an error on +// overflow. +// +// If the factorization in integers does not exists, the return value is (0, +// nil, nil). +// +// See also: +// https://en.wikipedia.org/wiki/Factorization_of_polynomials#Primitive_part.E2.80.93content_factorization +func QuadPolyFactors(a, b, c int) (content int, primitivePart []PolyFactor, _ error) { + content = int(GCDUint64(abs(a), GCDUint64(abs(b), abs(c)))) + switch { + case content == 0: + content = 1 + case content > 0: + if a < 0 || a == 0 && b < 0 { + content = -content + } + } + a /= content + b /= content + c /= content + if a == 0 { + if b == 0 { + return content, []PolyFactor{{0, c}}, nil + } + + if b < 0 && c < 0 { + b = -b + c = -c + } + if b < 0 { + b = -b + c = -c + } + return content, []PolyFactor{{b, c}}, nil + } + + ds, d, err := QuadPolyDiscriminant(a, b, c) + if err != nil { + return 0, nil, err + } + + if ds < 0 || d < 0 { + return 0, nil, nil + } + + x1num := -b + d + x1denom := 2 * a + gcd := int(GCDUint64(abs(x1num), abs(x1denom))) + x1num /= gcd + x1denom /= gcd + + x2num := -b - d + x2denom := 2 * a + gcd = int(GCDUint64(abs(x2num), abs(x2denom))) + x2num /= gcd + x2denom /= gcd + + return content, []PolyFactor{{x1denom, -x1num}, {x2denom, -x2num}}, nil +} + +// QuadPolyDiscriminantBig returns the discriminant of a quadratic polynomial +// in one variable of the form a*x^2+b*x+c with integer coefficients a, b, c. +// +// ds is the square of the discriminant. If |ds| is a square number, d is set +// to sqrt(|ds|), otherwise d is nil. +func QuadPolyDiscriminantBig(a, b, c *big.Int) (ds, d *big.Int) { + ds = big.NewInt(0).Set(b) + ds.Mul(ds, b) + x := big.NewInt(4) + x.Mul(x, a) + x.Mul(x, c) + ds.Sub(ds, x) + + s := big.NewInt(0).Set(ds) + if s.Sign() < 0 { + s.Neg(s) + } + + if s.Bit(1) != 0 { // s is not a square number + return ds, nil + } + + d = SqrtBig(s) + x.Set(d) + x.Mul(x, x) + if x.Cmp(s) != 0 { // s is not a square number + d = nil + } + return ds, d +} + +// PolyFactorBig describes an irreducible factor of a polynomial in one +// variable with integer coefficients P, Q of the form P*x+Q. +type PolyFactorBig struct { + P, Q *big.Int +} + +// QuadPolyFactorsBig returns the content and the irreducible factors of the +// primitive part of a quadratic polynomial in one variable with integer +// coefficients a, b, c of the form a*x^2+b*x+c in integers. +// +// If the factorization in integers does not exists, the return value is (nil, +// nil). +// +// See also: +// https://en.wikipedia.org/wiki/Factorization_of_polynomials#Primitive_part.E2.80.93content_factorization +func QuadPolyFactorsBig(a, b, c *big.Int) (content *big.Int, primitivePart []PolyFactorBig) { + content = bigGCD(bigAbs(a), bigGCD(bigAbs(b), bigAbs(c))) + switch { + case content.Sign() == 0: + content.SetInt64(1) + case content.Sign() > 0: + if a.Sign() < 0 || a.Sign() == 0 && b.Sign() < 0 { + content = bigNeg(content) + } + } + a = bigDiv(a, content) + b = bigDiv(b, content) + c = bigDiv(c, content) + + if a.Sign() == 0 { + if b.Sign() == 0 { + return content, []PolyFactorBig{{big.NewInt(0), c}} + } + + if b.Sign() < 0 && c.Sign() < 0 { + b = bigNeg(b) + c = bigNeg(c) + } + if b.Sign() < 0 { + b = bigNeg(b) + c = bigNeg(c) + } + return content, []PolyFactorBig{{b, c}} + } + + ds, d := QuadPolyDiscriminantBig(a, b, c) + if ds.Sign() < 0 || d == nil { + return nil, nil + } + + x1num := bigAdd(bigNeg(b), d) + x1denom := bigMul(_2, a) + gcd := bigGCD(bigAbs(x1num), bigAbs(x1denom)) + x1num = bigDiv(x1num, gcd) + x1denom = bigDiv(x1denom, gcd) + + x2num := bigAdd(bigNeg(b), bigNeg(d)) + x2denom := bigMul(_2, a) + gcd = bigGCD(bigAbs(x2num), bigAbs(x2denom)) + x2num = bigDiv(x2num, gcd) + x2denom = bigDiv(x2denom, gcd) + + return content, []PolyFactorBig{{x1denom, bigNeg(x1num)}, {x2denom, bigNeg(x2num)}} +} + +func bigAbs(n *big.Int) *big.Int { + n = big.NewInt(0).Set(n) + if n.Sign() >= 0 { + return n + } + + return n.Neg(n) +} + +func bigDiv(a, b *big.Int) *big.Int { + a = big.NewInt(0).Set(a) + return a.Div(a, b) +} + +func bigGCD(a, b *big.Int) *big.Int { + a = big.NewInt(0).Set(a) + b = big.NewInt(0).Set(b) + for b.Sign() != 0 { + c := big.NewInt(0) + c.Mod(a, b) + a, b = b, c + } + return a +} + +func bigNeg(n *big.Int) *big.Int { + n = big.NewInt(0).Set(n) + return n.Neg(n) +} + +func bigMul(a, b *big.Int) *big.Int { + r := big.NewInt(0).Set(a) + return r.Mul(r, b) +} + +func bigAdd(a, b *big.Int) *big.Int { + r := big.NewInt(0).Set(a) + return r.Add(r, b) +} |