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 | }
|
---|