gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

poly.go (5720B)


      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 }