source: code/trunk/vendor/modernc.org/mathutil/poly.go@ 822

Last change on this file since 822 was 822, checked in by yakumo.izuru, 22 months ago

Prefer immortal.run over runit and rc.d, use vendored modules
for convenience.

Signed-off-by: Izuru Yakumo <yakumo.izuru@…>

File size: 5.6 KB
RevLine 
[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
5package mathutil // import "modernc.org/mathutil"
6
7import (
8 "fmt"
9 "math/big"
10)
11
12func 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.
26func 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.
47type 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
61func 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.
119func 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.
147type 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
160func 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
210func 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
219func bigDiv(a, b *big.Int) *big.Int {
220 a = big.NewInt(0).Set(a)
221 return a.Div(a, b)
222}
223
224func 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
235func bigNeg(n *big.Int) *big.Int {
236 n = big.NewInt(0).Set(n)
237 return n.Neg(n)
238}
239
240func bigMul(a, b *big.Int) *big.Int {
241 r := big.NewInt(0).Set(a)
242 return r.Mul(r, b)
243}
244
245func bigAdd(a, b *big.Int) *big.Int {
246 r := big.NewInt(0).Set(a)
247 return r.Add(r, b)
248}
Note: See TracBrowser for help on using the repository browser.