// Copyright (c) 2014 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 (
	
)

// IsPrimeUint16 returns true if n is prime. Typical run time is few ns.
func ( uint16) bool {
	return  > 0 && primes16[-1] == 1
}

// NextPrimeUint16 returns first prime > n and true if successful or an
// undefined value and false if there is no next prime in the uint16 limits.
// Typical run time is few ns.
func ( uint16) ( uint16,  bool) {
	return  + uint16(primes16[]),  < 65521
}

// IsPrime returns true if n is prime. Typical run time is about 100 ns.
func ( uint32) bool {
	switch {
	case &1 == 0:
		return  == 2
	case %3 == 0:
		return  == 3
	case %5 == 0:
		return  == 5
	case %7 == 0:
		return  == 7
	case %11 == 0:
		return  == 11
	case %13 == 0:
		return  == 13
	case %17 == 0:
		return  == 17
	case %19 == 0:
		return  == 19
	case %23 == 0:
		return  == 23
	case %29 == 0:
		return  == 29
	case %31 == 0:
		return  == 31
	case %37 == 0:
		return  == 37
	case %41 == 0:
		return  == 41
	case %43 == 0:
		return  == 43
	case %47 == 0:
		return  == 47
	case %53 == 0:
		return  == 53 // Benchmarked optimum
	case  < 65536:
		// use table data
		return IsPrimeUint16(uint16())
	default:
		 := ModPowUint32(2, (+1)/2, )
		if  != 2 &&  != -2 {
			return false
		}
		 := &lohi[>>24]
		,  := .lo, .hi
		for  <=  {
			 := ( + ) >> 1
			 := liars[]
			switch {
			case  > :
				 =  + 1
			case  < :
				 =  - 1
			default:
				return false
			}
		}
		return true
	}
}

// IsPrimeUint64 returns true if n is prime. Typical run time is few tens of µs.
//
// SPRP bases: http://miller-rabin.appspot.com
func ( uint64) bool {
	switch {
	case %2 == 0:
		return  == 2
	case %3 == 0:
		return  == 3
	case %5 == 0:
		return  == 5
	case %7 == 0:
		return  == 7
	case %11 == 0:
		return  == 11
	case %13 == 0:
		return  == 13
	case %17 == 0:
		return  == 17
	case %19 == 0:
		return  == 19
	case %23 == 0:
		return  == 23
	case %29 == 0:
		return  == 29
	case %31 == 0:
		return  == 31
	case %37 == 0:
		return  == 37
	case %41 == 0:
		return  == 41
	case %43 == 0:
		return  == 43
	case %47 == 0:
		return  == 47
	case %53 == 0:
		return  == 53
	case %59 == 0:
		return  == 59
	case %61 == 0:
		return  == 61
	case %67 == 0:
		return  == 67
	case %71 == 0:
		return  == 71
	case %73 == 0:
		return  == 73
	case %79 == 0:
		return  == 79
	case %83 == 0:
		return  == 83
	case %89 == 0:
		return  == 89 // Benchmarked optimum
	case  <= math.MaxUint16:
		return IsPrimeUint16(uint16())
	case  <= math.MaxUint32:
		return ProbablyPrimeUint32(uint32(), 11000544) &&
			ProbablyPrimeUint32(uint32(), 31481107)
	case  < 105936894253:
		return ProbablyPrimeUint64_32(, 2) &&
			ProbablyPrimeUint64_32(, 1005905886) &&
			ProbablyPrimeUint64_32(, 1340600841)
	case  < 31858317218647:
		return ProbablyPrimeUint64_32(, 2) &&
			ProbablyPrimeUint64_32(, 642735) &&
			ProbablyPrimeUint64_32(, 553174392) &&
			ProbablyPrimeUint64_32(, 3046413974)
	case  < 3071837692357849:
		return ProbablyPrimeUint64_32(, 2) &&
			ProbablyPrimeUint64_32(, 75088) &&
			ProbablyPrimeUint64_32(, 642735) &&
			ProbablyPrimeUint64_32(, 203659041) &&
			ProbablyPrimeUint64_32(, 3613982119)
	default:
		return ProbablyPrimeUint64_32(, 2) &&
			ProbablyPrimeUint64_32(, 325) &&
			ProbablyPrimeUint64_32(, 9375) &&
			ProbablyPrimeUint64_32(, 28178) &&
			ProbablyPrimeUint64_32(, 450775) &&
			ProbablyPrimeUint64_32(, 9780504) &&
			ProbablyPrimeUint64_32(, 1795265022)
	}
}

// NextPrime returns first prime > n and true if successful or an undefined value and false if there
// is no next prime in the uint32 limits. Typical run time is about 2 µs.
func ( uint32) ( uint32,  bool) {
	switch {
	case  < 65521:
		,  := NextPrimeUint16(uint16())
		return uint32(), true
	case  >= math.MaxUint32-4:
		return
	}

	++
	var ,  uint32
	switch  :=  % 6;  {
	case 0:
		,  = 1, 4
	case 1:
		 = 4
	case 2, 3, 4:
		,  = 5-, 2
	case 5:
		 = 2
	}

	 =  + 
	if  <  { // overflow
		return
	}

	for {
		if IsPrime() {
			return , true
		}

		 := 
		 += 
		if  <  { // overflow
			break
		}

		 ^= 6
	}
	return
}

// NextPrimeUint64 returns first prime > n and true if successful or an undefined value and false if there
// is no next prime in the uint64 limits. Typical run time is in hundreds of µs.
func ( uint64) ( uint64,  bool) {
	switch {
	case  < 65521:
		,  := NextPrimeUint16(uint16())
		return uint64(), true
	case  >= 18446744073709551557: // last uint64 prime
		return
	}

	++
	var ,  uint64
	switch  :=  % 6;  {
	case 0:
		,  = 1, 4
	case 1:
		 = 4
	case 2, 3, 4:
		,  = 5-, 2
	case 5:
		 = 2
	}

	 =  + 
	if  <  { // overflow
		return
	}

	for {
		if  = IsPrimeUint64();  {
			break
		}

		 := 
		 += 
		if  <  { // overflow
			break
		}

		 ^= 6
	}
	return
}

// FactorTerm is one term of an integer factorization.
type FactorTerm struct {
	Prime uint32 // The divisor
	Power uint32 // Term == Prime^Power
}

// FactorTerms represent a factorization of an integer
type FactorTerms []FactorTerm

// FactorInt returns prime factorization of n > 1 or nil otherwise.
// Resulting factors are ordered by Prime. Typical run time is few µs.
func ( uint32) ( FactorTerms) {
	switch {
	case  < 2:
		return
	case IsPrime():
		return []FactorTerm{{, 1}}
	}

	,  := make([]FactorTerm, 9), 0
	for  := 2;  < len(primes16);  += int(primes16[]) {
		if uint(*) > uint() {
			break
		}

		 := uint32(0)
		for %uint32() == 0 {
			 /= uint32()
			++
		}
		if  != 0 {
			[] = FactorTerm{uint32(), }
			++
		}
		if  == 1 {
			break
		}
	}
	if  != 1 {
		[] = FactorTerm{, 1}
		++
	}
	return [:]
}

// PrimorialProductsUint32 returns a slice of numbers in [lo, hi] which are a
// product of max 'max' primorials. The slice is not sorted.
//
// See also: http://en.wikipedia.org/wiki/Primorial
func (, ,  uint32) ( []uint32) {
	,  := int64(), int64()
	if  > 31 { // N/A
		 = 31
	}

	var  func(int64, int64, uint32)
	 = func(,  int64,  uint32) {
		 := uint32(1)
		for  <=  &&  <=  {
			 *= 
			if  >=  &&  <=  {
				 = append(, uint32())
			}
			if  <  {
				,  := NextPrime(uint32())
				(, int64(), )
			}
			++
		}
	}

	(1, 2, )
	return
}