poly.go 5.6 KB

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