// 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 (
	
	
)

func ( int) uint64 {
	if  >= 0 {
		return uint64()
	}

	return uint64(-)
}

// 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 (, ,  int) (,  int,  error) {
	if 2*BitLenUint64(abs()) > IntBits-1 ||
		2+BitLenUint64(abs())+BitLenUint64(abs()) > IntBits-1 {
		return 0, 0, fmt.Errorf("overflow")
	}

	 = * - 4**
	 := 
	if  < 0 {
		 = -
	}
	 := SqrtUint64(uint64())
	if * != uint64() {
		return , -1, nil
	}

	return , int(), 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 (, ,  int) ( int,  []PolyFactor,  error) {
	 = int(GCDUint64(abs(), GCDUint64(abs(), abs())))
	switch {
	case  == 0:
		 = 1
	case  > 0:
		if  < 0 ||  == 0 &&  < 0 {
			 = -
		}
	}
	 /= 
	 /= 
	 /= 
	if  == 0 {
		if  == 0 {
			return , []PolyFactor{{0, }}, nil
		}

		if  < 0 &&  < 0 {
			 = -
			 = -
		}
		if  < 0 {
			 = -
			 = -
		}
		return , []PolyFactor{{, }}, nil
	}

	, ,  := QuadPolyDiscriminant(, , )
	if  != nil {
		return 0, nil, 
	}

	if  < 0 ||  < 0 {
		return 0, nil, nil
	}

	 := - + 
	 := 2 * 
	 := int(GCDUint64(abs(), abs()))
	 /= 
	 /= 

	 := - - 
	 := 2 * 
	 = int(GCDUint64(abs(), abs()))
	 /= 
	 /= 

	return , []PolyFactor{{, -}, {, -}}, 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 (, ,  *big.Int) (,  *big.Int) {
	 = big.NewInt(0).Set()
	.Mul(, )
	 := big.NewInt(4)
	.Mul(, )
	.Mul(, )
	.Sub(, )

	 := big.NewInt(0).Set()
	if .Sign() < 0 {
		.Neg()
	}

	if .Bit(1) != 0 { // s is not a square number
		return , nil
	}

	 = SqrtBig()
	.Set()
	.Mul(, )
	if .Cmp() != 0 { // s is not a square number
		 = nil
	}
	return , 
}

// 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 (, ,  *big.Int) ( *big.Int,  []PolyFactorBig) {
	 = bigGCD(bigAbs(), bigGCD(bigAbs(), bigAbs()))
	switch {
	case .Sign() == 0:
		.SetInt64(1)
	case .Sign() > 0:
		if .Sign() < 0 || .Sign() == 0 && .Sign() < 0 {
			 = bigNeg()
		}
	}
	 = bigDiv(, )
	 = bigDiv(, )
	 = bigDiv(, )

	if .Sign() == 0 {
		if .Sign() == 0 {
			return , []PolyFactorBig{{big.NewInt(0), }}
		}

		if .Sign() < 0 && .Sign() < 0 {
			 = bigNeg()
			 = bigNeg()
		}
		if .Sign() < 0 {
			 = bigNeg()
			 = bigNeg()
		}
		return , []PolyFactorBig{{, }}
	}

	,  := QuadPolyDiscriminantBig(, , )
	if .Sign() < 0 ||  == nil {
		return nil, nil
	}

	 := bigAdd(bigNeg(), )
	 := bigMul(_2, )
	 := bigGCD(bigAbs(), bigAbs())
	 = bigDiv(, )
	 = bigDiv(, )

	 := bigAdd(bigNeg(), bigNeg())
	 := bigMul(_2, )
	 = bigGCD(bigAbs(), bigAbs())
	 = bigDiv(, )
	 = bigDiv(, )

	return , []PolyFactorBig{{, bigNeg()}, {, bigNeg()}}
}

func ( *big.Int) *big.Int {
	 = big.NewInt(0).Set()
	if .Sign() >= 0 {
		return 
	}

	return .Neg()
}

func (,  *big.Int) *big.Int {
	 = big.NewInt(0).Set()
	return .Div(, )
}

func (,  *big.Int) *big.Int {
	 = big.NewInt(0).Set()
	 = big.NewInt(0).Set()
	for .Sign() != 0 {
		 := big.NewInt(0)
		.Mod(, )
		,  = , 
	}
	return 
}

func ( *big.Int) *big.Int {
	 = big.NewInt(0).Set()
	return .Neg()
}

func (,  *big.Int) *big.Int {
	 := big.NewInt(0).Set()
	return .Mul(, )
}

func (,  *big.Int) *big.Int {
	 := big.NewInt(0).Set()
	return .Add(, )
}