package fftpack

import (
	"math"
	"math/cmplx"
	"reflect"
	"testing"

	"github.com/jingcheng-WU/gonum/cmplxs"
	"github.com/jingcheng-WU/gonum/floats"
	"github.com/jingcheng-WU/gonum/floats/scalar"
)

func TestRfft(t *testing.T) {
	t.Parallel()

	for _, test := range rfftTests {
		const tol = 1e-12
		testRfft(t, test.n, tol, test.wantiwork, test.wantiifac)
	}

	for n := 1; n < 500; n++ {
		const tol = 1e-9
		testRfft(t, n, tol, nil, nil)
	}
}

func testRfft(t *testing.T, n int, tol float64, wantiwork []float64, wantiifac []int) {

	work := make([]float64, 2*n)
	ifac := make([]int, 15)
	Rffti(n, work, ifac)
	var failed bool
	if wantiwork != nil && !floats.EqualApprox(work, wantiwork, 1e-6) {
		failed = true
		t.Errorf("unexpected work after call to rffti for n=%d", n)
	}
	if wantiifac != nil && !reflect.DeepEqual(ifac, wantiifac) {
		failed = true
		t.Errorf("unexpected ifac after call to rffti for n=%d", n)
	}
	if failed {
		return
	}

	modn := n % 2
	fn := float64(n)
	nm1 := n - 1
	x, y, xh := series(n)

	dt := 2 * math.Pi / fn
	ns2 := (n + 1) / 2
	if ns2 >= 2 {
		for k := 1; k < ns2; k++ { 
			var sum1, sum2 float64
			arg := float64(k) * dt
			for i := 0; i < n; i++ {
				arg1 := float64(i) * arg
				sum1 += x[i] * math.Cos(arg1)
				sum2 += x[i] * math.Sin(arg1)
			}
			y[2*k-1] = sum1
			y[2*k] = -sum2
		}
	}
	var sum1, sum2 float64
	for i := 0; i < nm1; i += 2 {
		sum1 += x[i]
		sum2 += x[i+1]
	}
	if modn == 1 {
		sum1 += x[n-1]
	}
	y[0] = sum1 + sum2
	if modn == 0 {
		y[n-1] = sum1 - sum2
	}

	want := naiveDFTreal(x)

	Rfftf(n, x, work, ifac)

	if got := packCoeffs(x); !cmplxs.EqualApprox(got, want, tol) {
		t.Errorf("unexpected coefficients for n=%d: got:%f want:%f", n, got, want)
	}

	var rftf float64
	for i := 0; i < n; i++ {
		rftf = math.Max(rftf, math.Abs(x[i]-y[i]))
		x[i] = xh[i]
	}

	rftf /= fn
	if !scalar.EqualWithinAbsOrRel(rftf, 0, tol, tol) {
		t.Errorf("unexpected rftf value for n=%d: got:%f want:0", n, rftf)
	}

	for i := 0; i < n; i++ {
		sum := x[0] / 2
		arg := float64(i) * dt
		if ns2 >= 2 {
			for k := 1; k < ns2; k++ { 
				arg1 := float64(k) * arg
				sum += x[2*k-1]*math.Cos(arg1) - x[2*k]*math.Sin(arg1)
			}
		}
		if modn == 0 {

			sum += 0.5 * math.Pow(-1, float64(i)) * x[n-1]
		}
		y[i] = 2 * sum
	}
	Rfftb(n, x, work, ifac)
	var rftb float64
	for i := 0; i < n; i++ {
		rftb = math.Max(rftb, math.Abs(x[i]-y[i]))
		x[i] = xh[i]
		y[i] = xh[i]
	}
	if !scalar.EqualWithinAbsOrRel(rftb, 0, tol, tol) {
		t.Errorf("unexpected rftb value for n=%d: got:%g want:0", n, rftb)
	}

	Rfftb(n, y, work, ifac)
	Rfftf(n, y, work, ifac)
	cf := 1.0 / fn
	var rftfb float64
	for i := 0; i < n; i++ {
		rftfb = math.Max(rftfb, math.Abs(cf*y[i]-x[i]))
	}
	if !scalar.EqualWithinAbsOrRel(rftfb, 0, tol, tol) {
		t.Errorf("unexpected rftfb value for n=%d: got:%f want:0", n, rftfb)
	}
}

func naiveDFTreal(x []float64) (y []complex128) {
	y = make([]complex128, len(x))
	dt := -2 * math.Pi / float64(len(x))
	for i := range x {
		arg1 := float64(i) * dt
		for k, xv := range x {
			arg2 := float64(k) * arg1
			y[i] += complex(xv*math.Cos(arg2), xv*math.Sin(arg2))
		}
	}
	return y[:len(x)/2+1]
}

func packCoeffs(x []float64) []complex128 {
	y := make([]complex128, len(x)/2+1)
	y[0] = complex(x[0], 0)
	if len(x) < 2 {
		return y
	}
	if len(x)%2 == 1 {
		y[len(y)-1] = complex(x[len(x)-2], x[len(x)-1])
	} else {
		y[len(y)-1] = complex(x[len(x)-1], 0)
	}
	for i := 1; i < len(y)-1; i++ {
		y[i] = complex(x[2*i-1], x[2*i])
	}
	return y
}

var rfftTests = []struct {
	n int

	wantiwork []float64

	wantiifac []int
}{
	{
		n: 120,

		wantiwork: []float64{
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.9986295, 0.5233596e-01, 0.9945219, 0.1045285, 0.9876884, 0.1564345, 0.9781476, 0.2079117,
			0.9659258, 0.2588190, 0.9510565, 0.3090170, 0.9335804, 0.3583679, 0.9135454, 0.4067366,
			0.8910065, 0.4539905, 0.8660254, 0.5000000, 0.8386706, 0.5446391, 0.8090170, 0.5877852,
			0.7771459, 0.6293204, 0.7431448, 0.6691306, 0.7071068, 0.7071068, 0.6691306, 0.7431449,
			0.6293204, 0.7771460, 0.5877852, 0.8090170, 0.5446390, 0.8386706, 0.5000000, 0.8660254,
			0.4539905, 0.8910065, 0.4067366, 0.9135455, 0.3583679, 0.9335805, 0.3090170, 0.9510565,
			0.2588191, 0.9659258, 0.2079117, 0.9781476, 0.1564344, 0.9876884, 0.1045284, 0.9945219,
			0.5233597e-01, 0.9986295, 0.000000, 0.000000, 0.9945219, 0.1045285, 0.9781476, 0.2079117,
			0.9510565, 0.3090170, 0.9135454, 0.4067366, 0.8660254, 0.5000000, 0.8090170, 0.5877852,
			0.7431448, 0.6691306, 0.000000, 0.9781476, 0.2079117, 0.9135454, 0.4067366, 0.8090170,
			0.5877852, 0.6691306, 0.7431449, 0.5000000, 0.8660254, 0.3090170, 0.9510565, 0.1045284,
			0.9945219, 0.000000, 0.9510565, 0.3090170, 0.8090170, 0.5877852, 0.5877852, 0.8090170,
			0.3090170, 0.9510565, -0.4371139e-07, 1.000000, -0.3090170, 0.9510565, -0.5877852, 0.8090170,
			0.000000, 0.9135454, 0.4067366, 0.6691306, 0.7431449, 0.000000, 0.6691306, 0.7431449,
			-0.1045285, 0.9945219, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
		},
		wantiifac: []int{120, 4, 2, 4, 3, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 54,

		wantiwork: []float64{
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.9932383, 0.1160929,
			0.9730449, 0.2306159, 0.9396926, 0.3420201, 0.8936327, 0.4487992, 0.8354878, 0.5495090,
			0.7660444, 0.6427876, 0.6862416, 0.7273737, 0.5971586, 0.8021232, 0.5000000, 0.8660254,
			0.3960797, 0.9182161, 0.2868032, 0.9579895, 0.1736482, 0.9848077, 0.5814485e-01, 0.9983082,
			0.000000, 0.9730449, 0.2306159, 0.8936327, 0.4487992, 0.7660444, 0.6427876, 0.5971586,
			0.8021232, 0.000000, 0.8936327, 0.4487992, 0.5971586, 0.8021232, 0.1736482, 0.9848077,
			-0.2868032, 0.9579895, 0.000000, 0.7660444, 0.6427876, 0.000000, 0.1736482, 0.9848077,
			0.000000, 0.000000, 0.000000, 0.000000,
		},
		wantiifac: []int{54, 4, 2, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 49,

		wantiwork: []float64{
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.9917900, 0.1278772, 0.9672949, 0.2536546, 0.9269168, 0.3752670, 0.000000,
			0.9672949, 0.2536546, 0.8713187, 0.4907176, 0.7183493, 0.6956826, 0.000000, 0.9269168,
			0.3752670, 0.7183493, 0.6956826, 0.4047833, 0.9144127, 0.000000, 0.8713187, 0.4907176,
			0.5183925, 0.8551428, 0.3205151e-01, 0.9994862, 0.000000, 0.8014136, 0.5981106, 0.2845275,
			0.9586679, -0.3453652, 0.9384683, 0.000000, 0.7183493, 0.6956826, 0.3205151e-01, 0.9994862,
			-0.6723010, 0.7402779, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000,
		},
		wantiifac: []int{49, 2, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 32,

		wantiwork: []float64{
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.9807853, 0.1950903, 0.9238795, 0.3826835, 0.8314696, 0.5555702, 0.7071068, 0.7071068,
			0.5555702, 0.8314697, 0.3826834, 0.9238795, 0.1950902, 0.9807853, 0.000000, 0.000000,
			0.9238795, 0.3826835, 0.000000, 0.000000, 0.7071068, 0.7071068, 0.000000, 0.000000,
			0.3826834, 0.9238795, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
		},
		wantiifac: []int{32, 3, 2, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 25,

		wantiwork: []float64{
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.968583, 0.248690, 0.876307, 0.481754, 0.00000, 0.876307, 0.481754,
			0.535827, 0.844328, 0.00000, 0.728969, 0.684547, 0.627904e-01, 0.998027, 0.00000,
			0.535827, 0.844328, -0.425779, 0.904827, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000,
		},
		wantiifac: []int{25, 2, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 4,

		wantiwork: []float64{
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
		},
		wantiifac: []int{4, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 3,

		wantiwork: []float64{
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
		},
		wantiifac: []int{3, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 2,

		wantiwork: []float64{
			0.000000, 0.000000, 0.000000, 0.000000,
		},
		wantiifac: []int{2, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
}

func TestCfft(t *testing.T) {
	t.Parallel()

	const tol = 1e-12

	for _, test := range cfftTests {
		testCfft(t, test.n, tol, test.wantiwork, test.wantiifac)
	}

	for n := 1; n < 500; n++ {
		testCfft(t, n, tol, nil, nil)
	}
}

func testCfft(t *testing.T, n int, tol float64, wantiwork []float64, wantiifac []int) {

	work := make([]float64, 4*n)
	ifac := make([]int, 15)
	Cffti(n, work, ifac)
	var failed bool
	if wantiwork != nil && !floats.EqualApprox(work, wantiwork, 1e-6) {
		failed = true
		t.Errorf("unexpected work after call to cffti for n=%d", n)
	}
	if wantiifac != nil && !reflect.DeepEqual(ifac, wantiifac) {
		failed = true
		t.Errorf("unexpected ifac after call to cffti for n=%d", n)
	}
	if failed {
		return
	}

	fn := float64(n)
	cn := complex(fn, 0)

	x, y1 := cmplxSeries(n)

	want := naiveDFT(x)

	cx := cmplxAsFloat(x)
	Cfftf(n, cx, work, ifac)
	x = floatAsCmplx(cx)

	if !cmplxs.EqualApprox(x, want, tol*10) {
		t.Errorf("unexpected coefficients for n=%d: got:%f want:%f", n, x, want)
	}

	var cftf float64
	for i := 0; i < n; i++ {
		cftf = math.Max(cftf, cmplx.Abs(x[i]-y1[i]))
		x[i] /= cn
	}
	cftf /= fn

	if !scalar.EqualWithinAbsOrRel(cftf, 0, tol, tol) {
		t.Errorf("unexpected cftf value for n=%d: got:%f want:0", n, cftf)
	}

	y2 := updatedCmplxSeries(x)

	cx = cmplxAsFloat(x)
	Cfftb(n, cx, work, ifac)
	x = floatAsCmplx(cx)

	var cftb float64
	for i := 0; i < n; i++ {
		cftb = math.Max(cftb, cmplx.Abs(x[i]-y2[i]))
		x[i] = y2[i]
	}

	if !scalar.EqualWithinAbsOrRel(cftb, 0, tol, tol) {
		t.Errorf("unexpected cftb value for n=%d: got:%f want:0", n, cftb)
	}

	cx = cmplxAsFloat(x)
	Cfftf(n, cx, work, ifac)
	Cfftb(n, cx, work, ifac)
	x = floatAsCmplx(cx)

	var cftfb float64
	for i := 0; i < n; i++ {
		cftfb = math.Max(cftfb, cmplx.Abs(x[i]/cn-y2[i]))
	}

	if !scalar.EqualWithinAbsOrRel(cftfb, 0, tol, tol) {
		t.Errorf("unexpected cftfb value for n=%d: got:%f want:0", n, cftfb)
	}
}

func naiveDFT(x []complex128) (y []complex128) {
	y = make([]complex128, len(x))
	dt := -2 * math.Pi / float64(len(x))
	for i := range x {
		arg1 := float64(i) * dt
		for k, xv := range x {
			arg2 := float64(k) * arg1
			y[i] += complex(math.Cos(arg2), math.Sin(arg2)) * xv
		}
	}
	return y
}
func cmplxSeries(n int) (x, y []complex128) {
	x = make([]complex128, n)
	for i := 0; i < n; i++ {
		x[i] = complex(math.Cos(math.Sqrt2*float64(i+1)), math.Sin(math.Sqrt2*float64((i+1)*(i+1))))
	}

	y = make([]complex128, n)
	dt := 2 * math.Pi / float64(n)
	for i := 0; i < n; i++ {
		arg1 := -float64(i) * dt
		for k := 0; k < n; k++ {
			arg2 := float64(k) * arg1
			y[i] += complex(math.Cos(arg2), math.Sin(arg2)) * x[k]
		}
	}
	return x, y
}

func updatedCmplxSeries(x []complex128) (y []complex128) {
	y = make([]complex128, len(x))
	dt := 2 * math.Pi / float64(len(x))
	for i := range x {
		arg1 := float64(i) * dt
		for k, xv := range x {
			arg2 := float64(k) * arg1
			y[i] += complex(math.Cos(arg2), math.Sin(arg2)) * xv
		}
	}
	return y
}

func cmplxAsFloat(c []complex128) []float64 {
	f := make([]float64, 2*len(c))
	for i, v := range c {
		f[2*i] = real(v)
		f[2*i+1] = imag(v)
	}
	return f
}

func floatAsCmplx(f []float64) []complex128 {
	c := make([]complex128, len(f)/2)
	for i := range c {
		c[i] = complex(f[2*i], f[2*i+1])
	}
	return c
}

var cfftTests = []struct {
	n int

	wantiwork []float64

	wantiifac []int
}{
	{
		n: 120,

		wantiwork: []float64{
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			1.00000, 0.00000, 0.998630, 0.523360e-01, 0.994522, 0.104528, 0.987688, 0.156434,
			0.978148, 0.207912, 0.965926, 0.258819, 0.951057, 0.309017, 0.933580, 0.358368,
			0.913545, 0.406737, 0.891007, 0.453991, 0.866025, 0.500000, 0.838671, 0.544639,
			0.809017, 0.587785, 0.777146, 0.629320, 0.743145, 0.669131, 0.707107, 0.707107,
			0.669131, 0.743145, 0.629320, 0.777146, 0.587785, 0.809017, 0.544639, 0.838671,
			0.500000, 0.866025, 0.453991, 0.891007, 0.406737, 0.913545, 0.358368, 0.933580,
			0.309017, 0.951057, 0.258819, 0.965926, 0.207912, 0.978148, 0.156434, 0.987688,
			0.104528, 0.994522, 0.523360e-01, 0.998630, -0.437114e-07, 1.00000, -0.523361e-01, 0.998630,
			-0.104529, 0.994522, -0.156434, 0.987688, -0.207912, 0.978148, -0.258819, 0.965926,
			-0.309017, 0.951056, -0.358368, 0.933580, -0.406737, 0.913545, -0.453991, 0.891006,
			-0.500000, 0.866025, -0.544639, 0.838671, -0.587785, 0.809017, -0.629321, 0.777146,
			-0.669131, 0.743145, -0.707107, 0.707107, -0.743145, 0.669130, -0.777146, 0.629320,
			-0.809017, 0.587785, -0.838671, 0.544639, -0.866025, 0.500000, -0.891007, 0.453990,
			-0.913545, 0.406737, -0.933580, 0.358368, -0.951057, 0.309017, -0.965926, 0.258819,
			-0.978148, 0.207912, -0.987688, 0.156434, -0.994522, 0.104528, -0.998630, 0.523358e-01,
			1.00000, 0.00000, 0.994522, 0.104528, 0.978148, 0.207912, 0.951057, 0.309017,
			0.913545, 0.406737, 0.866025, 0.500000, 0.809017, 0.587785, 0.743145, 0.669131,
			0.669131, 0.743145, 0.587785, 0.809017, 0.500000, 0.866025, 0.406737, 0.913545,
			0.309017, 0.951057, 0.207912, 0.978148, 0.104528, 0.994522, -0.437114e-07, 1.00000,
			-0.104529, 0.994522, -0.207912, 0.978148, -0.309017, 0.951056, -0.406737, 0.913545,
			1.00000, 0.00000, 0.978148, 0.207912, 0.913545, 0.406737, 0.809017, 0.587785,
			0.669131, 0.743145, 0.500000, 0.866025, 0.309017, 0.951057, 0.104528, 0.994522,
			-0.104529, 0.994522, -0.309017, 0.951056, -0.500000, 0.866025, -0.669131, 0.743145,
			-0.809017, 0.587785, -0.913545, 0.406737, -0.978148, 0.207912, -1.00000, -0.874228e-07,
			-0.978148, -0.207912, -0.913545, -0.406737, -0.809017, -0.587785, -0.669131, -0.743145,
			1.00000, 0.00000, 0.951057, 0.309017, 0.809017, 0.587785, 0.587785, 0.809017,
			0.309017, 0.951057, 1.00000, 0.00000, 0.809017, 0.587785, 0.309017, 0.951057,
			-0.309017, 0.951056, -0.809017, 0.587785, 1.00000, 0.00000, 0.587785, 0.809017,
			-0.309017, 0.951056, -0.951057, 0.309017, -0.809017, -0.587785, 1.00000, 0.00000,
			1.00000, 0.00000, 1.00000, 0.00000, 1.00000, 0.00000, 0.309017, -0.951056,
		},
		wantiifac: []int{120, 4, 2, 3, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 54,

		wantiwork: []float64{
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 1.00000, 0.00000, 0.993238, 0.116093,
			0.973045, 0.230616, 0.939693, 0.342020, 0.893633, 0.448799, 0.835488, 0.549509,
			0.766044, 0.642788, 0.686242, 0.727374, 0.597159, 0.802123, 0.500000, 0.866025,
			0.396080, 0.918216, 0.286803, 0.957990, 0.173648, 0.984808, 0.581449e-01, 0.998308,
			-0.581448e-01, 0.998308, -0.173648, 0.984808, -0.286803, 0.957990, -0.396080, 0.918216,
			-0.500000, 0.866025, -0.597159, 0.802123, -0.686242, 0.727374, -0.766044, 0.642788,
			-0.835488, 0.549509, -0.893633, 0.448799, -0.939693, 0.342020, -0.973045, 0.230616,
			-0.993238, 0.116093, 1.00000, 0.00000, 0.973045, 0.230616, 0.893633, 0.448799,
			0.766044, 0.642788, 0.597159, 0.802123, 0.396080, 0.918216, 0.173648, 0.984808,
			-0.581448e-01, 0.998308, -0.286803, 0.957990, 1.00000, 0.00000, 0.893633, 0.448799,
			0.597159, 0.802123, 0.173648, 0.984808, -0.286803, 0.957990, -0.686242, 0.727374,
			-0.939693, 0.342020, -0.993238, -0.116093, -0.835488, -0.549509, 1.00000, 0.00000,
			0.766044, 0.642788, 0.173648, 0.984808, 1.00000, 0.00000, 0.173648, 0.984808,
			-0.939693, 0.342020, 1.00000, 0.00000, 1.00000, 0.00000, -0.500000, -0.866025,
		},
		wantiifac: []int{54, 4, 2, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 49,

		wantiwork: []float64{
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.623490, 0.781832, 0.991790, 0.127877, 0.967295, 0.253655,
			0.926917, 0.375267, 0.871319, 0.490718, 0.801414, 0.598111, 0.718349, 0.695683,
			-0.222521, 0.974928, 0.967295, 0.253655, 0.871319, 0.490718, 0.718349, 0.695683,
			0.518393, 0.855143, 0.284527, 0.958668, 0.320515e-01, 0.999486, -0.900969, 0.433884,
			0.926917, 0.375267, 0.718349, 0.695683, 0.404783, 0.914413, 0.320515e-01, 0.999486,
			-0.345365, 0.938468, -0.672301, 0.740278, -0.900969, -0.433884, 0.871319, 0.490718,
			0.518393, 0.855143, 0.320515e-01, 0.999486, -0.462538, 0.886599, -0.838088, 0.545535,
			-0.997945, 0.640701e-01, -0.222521, -0.974928, 0.801414, 0.598111, 0.284527, 0.958668,
			-0.345365, 0.938468, -0.838088, 0.545535, -0.997945, -0.640705e-01, -0.761446, -0.648229,
			0.623490, -0.781831, 0.718349, 0.695683, 0.320515e-01, 0.999486, -0.672301, 0.740278,
			-0.997945, 0.640701e-01, -0.761446, -0.648228, -0.960227e-01, -0.995379, 0.623490, 0.781832,
			-0.222521, 0.974928, -0.900969, 0.433884, -0.900969, -0.433884, -0.222521, -0.974928,
			0.623490, -0.781831, 0.623490, -0.781831,
		},
		wantiifac: []int{49, 2, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 32,

		wantiwork: []float64{
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			1.00000, 0.00000, 0.980785, 0.195090, 0.923880, 0.382683, 0.831470, 0.555570,
			0.707107, 0.707107, 0.555570, 0.831470, 0.382683, 0.923880, 0.195090, 0.980785,
			-0.437114e-07, 1.00000, -0.195090, 0.980785, -0.382684, 0.923880, -0.555570, 0.831470,
			-0.707107, 0.707107, -0.831470, 0.555570, -0.923880, 0.382683, -0.980785, 0.195090,
			1.00000, 0.00000, 0.923880, 0.382683, 0.707107, 0.707107, 0.382683, 0.923880,
			1.00000, 0.00000, 0.707107, 0.707107, -0.437114e-07, 1.00000, -0.707107, 0.707107,
			1.00000, 0.00000, 0.382683, 0.923880, -0.707107, 0.707107, -0.923880, -0.382683,
			1.00000, 0.00000, 1.00000, 0.00000, 1.00000, 0.00000, 0.119249e-07, -1.00000,
		},
		wantiifac: []int{32, 3, 2, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 25,

		wantiwork: []float64{
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 1.00000, 0.00000, 0.968583, 0.248690, 0.876307, 0.481754,
			0.728969, 0.684547, 0.535827, 0.844328, 1.00000, 0.00000, 0.876307, 0.481754,
			0.535827, 0.844328, 0.627904e-01, 0.998027, -0.425779, 0.904827, 1.00000, 0.00000,
			0.728969, 0.684547, 0.627904e-01, 0.998027, -0.637424, 0.770513, -0.992115, 0.125333,
			1.00000, 0.00000, 0.535827, 0.844328, -0.425779, 0.904827, -0.992115, 0.125333,
			-0.637424, -0.770513, 1.00000, 0.00000, 1.00000, 0.00000, 1.00000, 0.00000,
			1.00000, 0.00000, 0.309017, -0.951056,
		},
		wantiifac: []int{25, 2, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 4,

		wantiwork: []float64{
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			1.00000, 0.00000, 1.00000, 0.00000, 1.00000, 0.00000, 0.119249e-07, -1.00000,
		},
		wantiifac: []int{4, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 3,

		wantiwork: []float64{
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000, 0.00000,
			1.00000, 0.00000, -0.500000, -0.866025,
		},
		wantiifac: []int{3, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 2,

		wantiwork: []float64{
			0.00000, 0.00000, 0.00000, 0.00000, 1.00000, 0.00000, -1.00000, -0.874228e-07,
		},
		wantiifac: []int{2, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
}

func TestSint(t *testing.T) {
	t.Parallel()
	const tol = 1e-12
	for _, test := range sintTests {

		work := make([]float64, 5*(test.n)/2)
		ifac := make([]int, 15)
		Sinti(test.n-1, work, ifac)
		var failed bool
		if !floats.EqualApprox(work, test.wantiwork, 1e-6) {
			failed = true
			t.Errorf("unexpected work after call to sinti for n=%d", test.n)
		}
		if !reflect.DeepEqual(ifac, test.wantiifac) {
			failed = true
			t.Errorf("unexpected ifac after call to sinti for n=%d", test.n)
		}
		if failed {
			continue
		}

		fn := float64(test.n)
		x, _, xh := series(test.n - 1)
		y := make([]float64, test.n-1)

		dt := math.Pi / fn
		for i := 0; i < test.n-1; i++ {
			arg1 := float64(i+1) * dt
			for k := 0; k < test.n-1; k++ { 
				y[i] += x[k] * math.Sin(float64(k+1)*arg1)
			}
			y[i] *= 2
		}

		Sint(test.n-1, x, work, ifac)

		cf := 0.5 / fn
		var sintt float64
		for i := 0; i < test.n-1; i++ {
			sintt = math.Max(sintt, math.Abs(x[i]-y[i]))
			x[i] = xh[i]
			y[i] = x[i]
		}
		sintt *= cf
		if !scalar.EqualWithinAbsOrRel(sintt, 0, tol, tol) {
			t.Errorf("unexpected sintt value for n=%d: got:%f want:0", test.n, sintt)
		}

		Sint(test.n-1, x, work, ifac)
		Sint(test.n-1, x, work, ifac)

		var sintfb float64
		for i := 0; i < test.n-1; i++ {
			sintfb = math.Max(sintfb, math.Abs(cf*x[i]-y[i]))
		}
		if !scalar.EqualWithinAbsOrRel(sintfb, 0, tol, tol) {
			t.Errorf("unexpected sintfb value for n=%d: got:%f want:0", test.n, sintfb)
		}
	}
}

var sintTests = []struct {
	n int

	wantiwork []float64

	wantiifac []int
}{
	{
		n: 120,

		wantiwork: []float64{
			0.5235390e-01, 0.1046719, 0.1569182, 0.2090569, 0.2610524, 0.3128690, 0.3644710, 0.4158234,
			0.4668908, 0.5176381, 0.5680307, 0.6180340, 0.6676137, 0.7167359, 0.7653669, 0.8134733,
			0.8610222, 0.9079810, 0.9543176, 1.000000, 1.044997, 1.089278, 1.132812, 1.175570,
			1.217523, 1.258641, 1.298896, 1.338261, 1.376709, 1.414214, 1.450749, 1.486290,
			1.520812, 1.554292, 1.586707, 1.618034, 1.648252, 1.677341, 1.705280, 1.732051,
			1.757634, 1.782013, 1.805171, 1.827091, 1.847759, 1.867161, 1.885283, 1.902113,
			1.917639, 1.931852, 1.944740, 1.956295, 1.966510, 1.975377, 1.982890, 1.989044,
			1.993835, 1.997259, 1.999315, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.9986295, 0.5233596e-01, 0.9945219, 0.1045285, 0.9876884,
			0.1564345, 0.9781476, 0.2079117, 0.9659258, 0.2588190, 0.9510565, 0.3090170, 0.9335804,
			0.3583679, 0.9135454, 0.4067366, 0.8910065, 0.4539905, 0.8660254, 0.5000000, 0.8386706,
			0.5446391, 0.8090170, 0.5877852, 0.7771459, 0.6293204, 0.7431448, 0.6691306, 0.7071068,
			0.7071068, 0.6691306, 0.7431449, 0.6293204, 0.7771460, 0.5877852, 0.8090170, 0.5446390,
			0.8386706, 0.5000000, 0.8660254, 0.4539905, 0.8910065, 0.4067366, 0.9135455, 0.3583679,
			0.9335805, 0.3090170, 0.9510565, 0.2588191, 0.9659258, 0.2079117, 0.9781476, 0.1564344,
			0.9876884, 0.1045284, 0.9945219, 0.5233597e-01, 0.9986295, 0.000000, 0.000000, 0.9945219,
			0.1045285, 0.9781476, 0.2079117, 0.9510565, 0.3090170, 0.9135454, 0.4067366, 0.8660254,
			0.5000000, 0.8090170, 0.5877852, 0.7431448, 0.6691306, 0.000000, 0.9781476, 0.2079117,
			0.9135454, 0.4067366, 0.8090170, 0.5877852, 0.6691306, 0.7431449, 0.5000000, 0.8660254,
			0.3090170, 0.9510565, 0.1045284, 0.9945219, 0.000000, 0.9510565, 0.3090170, 0.8090170,
			0.5877852, 0.5877852, 0.8090170, 0.3090170, 0.9510565, -0.4371139e-07, 1.000000, -0.3090170,
			0.9510565, -0.5877852, 0.8090170, 0.000000, 0.9135454, 0.4067366, 0.6691306, 0.7431449,
			0.000000, 0.6691306, 0.7431449, -0.1045285, 0.9945219, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.1681558e-42,
		},
		wantiifac: []int{120, 4, 2, 4, 3, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 54,

		wantiwork: []float64{
			0.1162897, 0.2321858, 0.3472964, 0.4612317, 0.5736065, 0.6840402, 0.7921596, 0.8975984,
			1.000000, 1.099018, 1.194317, 1.285575, 1.372483, 1.454747, 1.532089, 1.604246,
			1.670976, 1.732051, 1.787265, 1.836432, 1.879385, 1.915979, 1.946090, 1.969615,
			1.986477, 1.996616, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.9932383, 0.1160929, 0.9730449, 0.2306159, 0.9396926, 0.3420201, 0.8936327, 0.4487992,
			0.8354878, 0.5495090, 0.7660444, 0.6427876, 0.6862416, 0.7273737, 0.5971586, 0.8021232,
			0.5000000, 0.8660254, 0.3960797, 0.9182161, 0.2868032, 0.9579895, 0.1736482, 0.9848077,
			0.5814485e-01, 0.9983082, 0.000000, 0.9730449, 0.2306159, 0.8936327, 0.4487992, 0.7660444,
			0.6427876, 0.5971586, 0.8021232, 0.000000, 0.8936327, 0.4487992, 0.5971586, 0.8021232,
			0.1736482, 0.9848077, -0.2868032, 0.9579895, 0.000000, 0.7660444, 0.6427876, 0.000000,
			0.1736482, 0.9848077, 0.000000, 0.000000, 0.000000, 0.000000, 0.7567012e-43,
		},
		wantiifac: []int{54, 4, 2, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 49,

		wantiwork: []float64{
			0.1281404, 0.2557543, 0.3823173, 0.5073092, 0.6302165, 0.7505341, 0.8677675, 0.9814351,
			1.091070, 1.196221, 1.296457, 1.391365, 1.480556, 1.563663, 1.640345, 1.710286,
			1.773199, 1.828825, 1.876937, 1.917336, 1.949856, 1.974364, 1.990758, 1.998972,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.9917900, 0.1278772, 0.9672949, 0.2536546, 0.9269168, 0.3752670, 0.000000,
			0.9672949, 0.2536546, 0.8713187, 0.4907176, 0.7183493, 0.6956826, 0.000000, 0.9269168,
			0.3752670, 0.7183493, 0.6956826, 0.4047833, 0.9144127, 0.000000, 0.8713187, 0.4907176,
			0.5183925, 0.8551428, 0.3205151e-01, 0.9994862, 0.000000, 0.8014136, 0.5981106, 0.2845275,
			0.9586679, -0.3453652, 0.9384683, 0.000000, 0.7183493, 0.6956826, 0.3205151e-01, 0.9994862,
			-0.6723010, 0.7402779, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000,
		},
		wantiifac: []int{49, 2, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 32,

		wantiwork: []float64{
			0.1960343, 0.3901806, 0.5805693, 0.7653669, 0.9427935, 1.111140, 1.268787, 1.414214,
			1.546021, 1.662939, 1.763843, 1.847759, 1.913881, 1.961571, 1.990369, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.9807853,
			0.1950903, 0.9238795, 0.3826835, 0.8314696, 0.5555702, 0.7071068, 0.7071068, 0.5555702,
			0.8314697, 0.3826834, 0.9238795, 0.1950902, 0.9807853, 0.000000, 0.000000, 0.9238795,
			0.3826835, 0.000000, 0.000000, 0.7071068, 0.7071068, 0.000000, 0.000000, 0.3826834,
			0.9238795, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.4484155e-43,
		},
		wantiifac: []int{32, 3, 2, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 25,

		wantiwork: []float64{
			0.2506665, 0.4973798, 0.7362491, 0.9635074, 1.175570, 1.369094, 1.541027, 1.688656,
			1.809654, 1.902113, 1.964575, 1.996053, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.9685832, 0.2486899, 0.8763067,
			0.4817537, 0.000000, 0.8763067, 0.4817537, 0.5358267, 0.8443279, 0.000000, 0.7289686,
			0.6845471, 0.6279038e-01, 0.9980267, 0.000000, 0.5358267, 0.8443279, -0.4257794, 0.9048270,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
		},
		wantiifac: []int{25, 2, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 4,

		wantiwork: []float64{
			1.414214, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000,
		},
		wantiifac: []int{4, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 3,

		wantiwork: []float64{
			1.732051, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
		},
		wantiifac: []int{3, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 2,

		wantiwork: []float64{
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
		},
		wantiifac: []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
}

func TestCost(t *testing.T) {
	t.Parallel()
	const tol = 1e-12
	for _, test := range costTests {

		work := make([]float64, 3*(test.n+1))
		ifac := make([]int, 15)
		Costi(test.n+1, work, ifac)
		var failed bool
		if !floats.EqualApprox(work, test.wantiwork, 1e-6) {
			failed = true
			t.Errorf("unexpected work after call to costi for n=%d", test.n)
		}
		if !reflect.DeepEqual(ifac, test.wantiifac) {
			failed = true
			t.Errorf("unexpected ifac after call to costi for n=%d", test.n)
		}
		if failed {
			continue
		}

		fn := float64(test.n)
		x, _, xh := series(test.n + 1)
		y := make([]float64, test.n+1)

		dt := math.Pi / fn
		for i := 0; i < test.n+1; i++ {
			y[i] = 0.5 * (x[0] + math.Pow(-1, float64(i))*x[test.n])
			arg1 := float64(i) * dt
			for k := 1; k < test.n; k++ { 
				y[i] += x[k] * math.Cos(float64(k)*arg1)
			}
			y[i] *= 2
		}

		Cost(test.n+1, x, work, ifac)

		cf := 0.5 / fn
		var costt float64
		for i := 0; i < test.n; i++ {
			costt = math.Max(costt, math.Abs(x[i]-y[i]))
			x[i] = xh[i]
			y[i] = x[i]
		}
		costt *= cf
		if !scalar.EqualWithinAbsOrRel(costt, 0, tol, tol) {
			t.Errorf("unexpected costt value for n=%d: got:%f want:0", test.n, costt)
		}

		Cost(test.n+1, x, work, ifac)
		Cost(test.n+1, x, work, ifac)

		var costfb float64
		for i := 0; i < test.n-1; i++ {
			costfb = math.Max(costfb, math.Abs(cf*x[i]-y[i]))
		}
		if !scalar.EqualWithinAbsOrRel(costfb, 0, tol, tol) {
			t.Errorf("unexpected costfb value for n=%d: got:%f want:0", test.n, costfb)
		}
	}
}

var costTests = []struct {
	n int

	wantiwork []float64

	wantiifac []int
}{
	{
		n: 120,

		wantiwork: []float64{
			0.000000, 0.5235390e-01, 0.1046719, 0.1569182, 0.2090569, 0.2610524, 0.3128690, 0.3644710,
			0.4158234, 0.4668908, 0.5176381, 0.5680307, 0.6180340, 0.6676137, 0.7167359, 0.7653669,
			0.8134733, 0.8610222, 0.9079810, 0.9543176, 1.000000, 1.044997, 1.089278, 1.132812,
			1.175570, 1.217523, 1.258641, 1.298896, 1.338261, 1.376709, 1.414214, 1.450749,
			1.486290, 1.520812, 1.554292, 1.586707, 1.618034, 1.648252, 1.677341, 1.705280,
			1.732051, 1.757634, 1.782013, 1.805171, 1.827091, 1.847759, 1.867161, 1.885283,
			1.902113, 1.917639, 1.931852, 1.944740, 1.956295, 1.966510, 1.975377, 1.982890,
			1.989044, 1.993835, 1.997259, 1.999315, 0.000000, 0.5235375e-01, 0.1046719, 0.1569182,
			0.2090568, 0.2610523, 0.3128687, 0.3644710, 0.4158233, 0.4668906, 0.5176381, 0.5680307,
			0.6180339, 0.6676136, 0.7167357, 0.7653669, 0.8134732, 0.8610221, 0.9079810, 0.9543175,
			1.000000, 1.044997, 1.089278, 1.132812, 1.175570, 1.217523, 1.258641, 1.298896,
			1.338261, 1.376709, 1.414214, 1.450749, 1.486290, 1.520812, 1.554292, 1.586707,
			1.618034, 1.648252, 1.677341, 1.705280, 1.732051, 1.757634, 1.782013, 1.805171,
			1.827091, 1.847759, 1.867161, 1.885283, 1.902113, 1.917639, 1.931852, 1.944740,
			1.956295, 1.966510, 1.975377, 1.982890, 1.989044, 1.993835, 1.997259, 1.999315,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.9986295, 0.5233596e-01, 0.9945219, 0.1045285, 0.9876884, 0.1564345, 0.9781476,
			0.2079117, 0.9659258, 0.2588190, 0.9510565, 0.3090170, 0.9335804, 0.3583679, 0.9135454,
			0.4067366, 0.8910065, 0.4539905, 0.8660254, 0.5000000, 0.8386706, 0.5446391, 0.8090170,
			0.5877852, 0.7771459, 0.6293204, 0.7431448, 0.6691306, 0.7071068, 0.7071068, 0.6691306,
			0.7431449, 0.6293204, 0.7771460, 0.5877852, 0.8090170, 0.5446390, 0.8386706, 0.5000000,
			0.8660254, 0.4539905, 0.8910065, 0.4067366, 0.9135455, 0.3583679, 0.9335805, 0.3090170,
			0.9510565, 0.2588191, 0.9659258, 0.2079117, 0.9781476, 0.1564344, 0.9876884, 0.1045284,
			0.9945219, 0.5233597e-01, 0.9986295, 0.000000, 0.000000, 0.9945219, 0.1045285, 0.9781476,
			0.2079117, 0.9510565, 0.3090170, 0.9135454, 0.4067366, 0.8660254, 0.5000000, 0.8090170,
			0.5877852, 0.7431448, 0.6691306, 0.000000, 0.9781476, 0.2079117, 0.9135454, 0.4067366,
			0.8090170, 0.5877852, 0.6691306, 0.7431449, 0.5000000, 0.8660254, 0.3090170, 0.9510565,
			0.1045284, 0.9945219, 0.000000, 0.9510565, 0.3090170, 0.8090170, 0.5877852, 0.5877852,
			0.8090170, 0.3090170, 0.9510565, -0.4371139e-07, 1.000000, -0.3090170, 0.9510565, -0.5877852,
			0.8090170, 0.000000, 0.9135454, 0.4067366, 0.6691306, 0.7431449, 0.000000, 0.6691306,
			0.7431449, -0.1045285, 0.9945219, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.1681558e-42, 0.5605194e-44,
		},
		wantiifac: []int{120, 4, 2, 4, 3, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 54,

		wantiwork: []float64{
			0.000000, 0.1162897, 0.2321858, 0.3472964, 0.4612317, 0.5736065, 0.6840402, 0.7921596,
			0.8975984, 1.000000, 1.099018, 1.194317, 1.285575, 1.372483, 1.454747, 1.532089,
			1.604246, 1.670976, 1.732051, 1.787265, 1.836432, 1.879385, 1.915979, 1.946090,
			1.969615, 1.986477, 1.996616, 0.000000, 0.1162897, 0.2321858, 0.3472964, 0.4612317,
			0.5736064, 0.6840403, 0.7921594, 0.8975984, 1.000000, 1.099018, 1.194317, 1.285575,
			1.372483, 1.454747, 1.532089, 1.604246, 1.670976, 1.732051, 1.787265, 1.836432,
			1.879385, 1.915979, 1.946090, 1.969615, 1.986477, 1.996616, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.9932383, 0.1160929, 0.9730449,
			0.2306159, 0.9396926, 0.3420201, 0.8936327, 0.4487992, 0.8354878, 0.5495090, 0.7660444,
			0.6427876, 0.6862416, 0.7273737, 0.5971586, 0.8021232, 0.5000000, 0.8660254, 0.3960797,
			0.9182161, 0.2868032, 0.9579895, 0.1736482, 0.9848077, 0.5814485e-01, 0.9983082, 0.000000,
			0.9730449, 0.2306159, 0.8936327, 0.4487992, 0.7660444, 0.6427876, 0.5971586, 0.8021232,
			0.000000, 0.8936327, 0.4487992, 0.5971586, 0.8021232, 0.1736482, 0.9848077, -0.2868032,
			0.9579895, 0.000000, 0.7660444, 0.6427876, 0.000000, 0.1736482, 0.9848077, 0.000000,
			0.000000, 0.000000, 0.000000, 0.7567012e-43, 0.5605194e-44,
		},
		wantiifac: []int{54, 4, 2, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 49,

		wantiwork: []float64{
			0.000000, 0.1281404, 0.2557543, 0.3823173, 0.5073092, 0.6302165, 0.7505341, 0.8677675,
			0.9814351, 1.091070, 1.196221, 1.296457, 1.391365, 1.480556, 1.563663, 1.640345,
			1.710286, 1.773199, 1.828825, 1.876937, 1.917336, 1.949856, 1.974364, 1.990758,
			1.998972, 0.6410302e-01, 0.1920458, 0.3191997, 0.4450417, 0.5690550, 0.6907300, 0.8095666,
			0.9250766, 1.036785, 1.144233, 1.246980, 1.344602, 1.436699, 1.522892, 1.602827,
			1.676176, 1.742637, 1.801938, 1.853834, 1.898111, 1.934590, 1.963118, 1.983580,
			1.995891, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.9917900, 0.1278772, 0.9672949, 0.2536546, 0.9269168,
			0.3752670, 0.000000, 0.9672949, 0.2536546, 0.8713187, 0.4907176, 0.7183493, 0.6956826,
			0.000000, 0.9269168, 0.3752670, 0.7183493, 0.6956826, 0.4047833, 0.9144127, 0.000000,
			0.8713187, 0.4907176, 0.5183925, 0.8551428, 0.3205151e-01, 0.9994862, 0.000000, 0.8014136,
			0.5981106, 0.2845275, 0.9586679, -0.3453652, 0.9384683, 0.000000, 0.7183493, 0.6956826,
			0.3205151e-01, 0.9994862, -0.6723010, 0.7402779, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.6866362e-43, 0.2802597e-44,
		},
		wantiifac: []int{49, 2, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 32,

		wantiwork: []float64{
			0.000000, 0.1960343, 0.3901806, 0.5805693, 0.7653669, 0.9427935, 1.111140, 1.268787,
			1.414214, 1.546021, 1.662939, 1.763843, 1.847759, 1.913881, 1.961571, 1.990369,
			0.000000, 0.1960343, 0.3901805, 0.5805693, 0.7653669, 0.9427933, 1.111140, 1.268787,
			1.414214, 1.546021, 1.662939, 1.763842, 1.847759, 1.913881, 1.961571, 1.990369,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.9807853, 0.1950903, 0.9238795, 0.3826835, 0.8314696, 0.5555702, 0.7071068,
			0.7071068, 0.5555702, 0.8314697, 0.3826834, 0.9238795, 0.1950902, 0.9807853, 0.000000,
			0.000000, 0.9238795, 0.3826835, 0.000000, 0.000000, 0.7071068, 0.7071068, 0.000000,
			0.000000, 0.3826834, 0.9238795, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.4484155e-43, 0.4203895e-44,
		},
		wantiifac: []int{32, 3, 2, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 25,

		wantiwork: []float64{
			0.000000, 0.2506665, 0.4973798, 0.7362491, 0.9635074, 1.175570, 1.369094, 1.541027,
			1.688656, 1.809654, 1.902113, 1.964575, 1.996053, 0.1255808, 0.3747624, 0.6180339,
			0.8515584, 1.071653, 1.274848, 1.457937, 1.618034, 1.752613, 1.859553, 1.937166,
			1.984229, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.9685832, 0.2486899, 0.8763067, 0.4817537, 0.000000,
			0.8763067, 0.4817537, 0.5358267, 0.8443279, 0.000000, 0.7289686, 0.6845471, 0.6279038e-01,
			0.9980267, 0.000000, 0.5358267, 0.8443279, -0.4257794, 0.9048270, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.3503246e-43, 0.2802597e-44,
		},
		wantiifac: []int{25, 2, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 4,

		wantiwork: []float64{
			0.000000, 1.414214, 0.000000, 1.414214, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.5605194e-44, 0.1401298e-44,
		},
		wantiifac: []int{4, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 3,

		wantiwork: []float64{
			0.000000, 1.732051, 1.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.4203895e-44, 0.1401298e-44,
		},
		wantiifac: []int{3, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 2,

		wantiwork: []float64{
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000,
		},
		wantiifac: []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
}

func TestCosq(t *testing.T) {
	t.Parallel()
	const tol = 1e-12
	for _, test := range sincosqTests {

		work := make([]float64, 3*test.n)
		ifac := make([]int, 15)
		Cosqi(test.n, work, ifac)
		var failed bool
		if !floats.EqualApprox(work, test.wantiwork, 1e-6) {
			failed = true
			t.Errorf("unexpected work after call to cosqi for n=%d", test.n)
			t.Logf("\n%v\n%v", work, test.wantiwork)
		}
		if !reflect.DeepEqual(ifac, test.wantiifac) {
			failed = true
			t.Errorf("unexpected ifac after call to cosqi for n=%d", test.n)
		}
		if failed {
			continue
		}

		fn := float64(test.n)
		x := make([]float64, test.n)
		y, _, xh := series(test.n)

		dt := math.Pi / (2 * fn)
		for i := 0; i < test.n; i++ {
			arg := float64(i) * dt
			for k := 0; k < test.n; k++ {
				x[i] += y[k] * math.Cos(float64(2*k+1)*arg)
			}
			x[i] *= 4
		}

		Cosqb(test.n, y, work, ifac)

		cf := 0.25 / fn
		var cosqbt float64
		for i := 0; i < test.n; i++ {
			cosqbt = math.Max(cosqbt, math.Abs(x[i]-y[i]))
			x[i] = xh[i]
		}
		cosqbt *= cf
		if !scalar.EqualWithinAbsOrRel(cosqbt, 0, tol, tol) {
			t.Errorf("unexpected cosqbt value for n=%d: got:%f want:0", test.n, cosqbt)
		}

		for i := 0; i < test.n; i++ {
			y[i] = 0.5 * x[0]
			arg := float64(2*i+1) * dt
			for k := 1; k < test.n; k++ {
				y[i] += x[k] * math.Cos(float64(k)*arg)
			}
			y[i] *= 2
		}

		Cosqf(test.n, x, work, ifac)

		var cosqft float64
		for i := 0; i < test.n; i++ {
			cosqft = math.Max(cosqft, math.Abs(x[i]-y[i]))
			x[i] = xh[i]
			y[i] = xh[i]
		}
		cosqft *= cf
		if !scalar.EqualWithinAbsOrRel(cosqft, 0, tol, tol) {
			t.Errorf("unexpected cosqft value for n=%d: got:%f want:0", test.n, cosqft)
		}

		Cosqb(test.n, x, work, ifac)
		Cosqf(test.n, x, work, ifac)

		var cosqfb float64
		for i := 0; i < test.n; i++ {
			cosqfb = math.Max(cosqfb, math.Abs(cf*x[i]-y[i]))
		}
		if !scalar.EqualWithinAbsOrRel(cosqfb, 0, tol, tol) {
			t.Errorf("unexpected cosqfb value for n=%d: got:%f want:0", test.n, cosqfb)
		}
	}
}

func TestSinq(t *testing.T) {
	t.Parallel()
	const tol = 1e-12
	for _, test := range sincosqTests {

		work := make([]float64, 3*test.n)
		ifac := make([]int, 15)
		Sinqi(test.n, work, ifac)
		var failed bool
		if !floats.EqualApprox(work, test.wantiwork, 1e-6) {
			failed = true
			t.Errorf("unexpected work after call to sinqi for n=%d", test.n)
			t.Logf("\n%v\n%v", work, test.wantiwork)
		}
		if !reflect.DeepEqual(ifac, test.wantiifac) {
			failed = true
			t.Errorf("unexpected ifac after call to sinqi for n=%d", test.n)
		}
		if failed {
			continue
		}

		fn := float64(test.n)
		x := make([]float64, test.n)
		y, _, xh := series(test.n)

		dt := math.Pi / (2 * fn)
		for i := 0; i < test.n; i++ {
			arg := float64(i+1) * dt
			for k := 0; k < test.n; k++ {
				x[i] += y[k] * math.Sin(float64(2*k+1)*arg)
			}
			x[i] *= 4
		}

		Sinqb(test.n, y, work, ifac)

		cf := 0.25 / fn
		var sinqbt float64
		for i := 0; i < test.n; i++ {
			sinqbt = math.Max(sinqbt, math.Abs(x[i]-y[i]))
			x[i] = xh[i]
		}
		sinqbt *= cf
		if !scalar.EqualWithinAbsOrRel(sinqbt, 0, tol, tol) {
			t.Errorf("unexpected sinqbt value for n=%d: got:%f want:0", test.n, sinqbt)
		}

		for i := 0; i < test.n; i++ {
			arg := float64(2*i+1) * dt
			y[i] = 0.5 * math.Pow(-1, float64(i)) * x[test.n-1]
			for k := 0; k < test.n-1; k++ {
				y[i] += x[k] * math.Sin(float64(k+1)*arg)
			}
			y[i] *= 2
		}

		Sinqf(test.n, x, work, ifac)

		var sinqft float64
		for i := 0; i < test.n; i++ {
			sinqft = math.Max(sinqft, math.Abs(x[i]-y[i]))
			x[i] = xh[i]
			y[i] = xh[i]
		}
		sinqft *= cf
		if !scalar.EqualWithinAbsOrRel(sinqft, 0, tol, tol) {
			t.Errorf("unexpected sinqft value for n=%d: got:%f want:0", test.n, sinqft)
		}

		Sinqb(test.n, x, work, ifac)
		Sinqf(test.n, x, work, ifac)

		var sinqfb float64
		for i := 0; i < test.n; i++ {
			sinqfb = math.Max(sinqfb, math.Abs(cf*x[i]-y[i]))
		}
		if !scalar.EqualWithinAbsOrRel(sinqfb, 0, tol, tol) {
			t.Errorf("unexpected sinqfb value for n=%d: got:%f want:0", test.n, sinqfb)
		}
	}
}

var sincosqTests = []struct {
	n int

	wantiwork []float64

	wantiifac []int
}{
	{
		n: 120,

		wantiwork: []float64{
			0.9999143, 0.9996573, 0.9992290, 0.9986295, 0.9978589, 0.9969173, 0.9958049, 0.9945219,
			0.9930685, 0.9914449, 0.9896514, 0.9876884, 0.9855561, 0.9832549, 0.9807853, 0.9781476,
			0.9753423, 0.9723699, 0.9692309, 0.9659258, 0.9624552, 0.9588197, 0.9550200, 0.9510565,
			0.9469301, 0.9426415, 0.9381914, 0.9335804, 0.9288096, 0.9238795, 0.9187912, 0.9135454,
			0.9081432, 0.9025853, 0.8968728, 0.8910065, 0.8849877, 0.8788171, 0.8724960, 0.8660254,
			0.8594064, 0.8526402, 0.8457278, 0.8386706, 0.8314696, 0.8241262, 0.8166415, 0.8090170,
			0.8012538, 0.7933533, 0.7853169, 0.7771459, 0.7688418, 0.7604060, 0.7518398, 0.7431448,
			0.7343225, 0.7253744, 0.7163019, 0.7071068, 0.6977904, 0.6883546, 0.6788007, 0.6691306,
			0.6593458, 0.6494480, 0.6394390, 0.6293204, 0.6190940, 0.6087614, 0.5983246, 0.5877852,
			0.5771452, 0.5664062, 0.5555702, 0.5446390, 0.5336145, 0.5224985, 0.5112931, 0.5000000,
			0.4886212, 0.4771588, 0.4656145, 0.4539905, 0.4422887, 0.4305110, 0.4186597, 0.4067366,
			0.3947438, 0.3826834, 0.3705574, 0.3583679, 0.3461170, 0.3338068, 0.3214395, 0.3090170,
			0.2965415, 0.2840153, 0.2714404, 0.2588191, 0.2461533, 0.2334453, 0.2206974, 0.2079117,
			0.1950902, 0.1822355, 0.1693494, 0.1564344, 0.1434926, 0.1305261, 0.1175374, 0.1045284,
			0.9150153e-01, 0.7845908e-01, 0.6540307e-01, 0.5233597e-01, 0.3925979e-01, 0.2617688e-01, 0.1308960e-01, -0.4371139e-07,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.9986295, 0.5233596e-01, 0.9945219, 0.1045285, 0.9876884, 0.1564345, 0.9781476, 0.2079117,
			0.9659258, 0.2588190, 0.9510565, 0.3090170, 0.9335804, 0.3583679, 0.9135454, 0.4067366,
			0.8910065, 0.4539905, 0.8660254, 0.5000000, 0.8386706, 0.5446391, 0.8090170, 0.5877852,
			0.7771459, 0.6293204, 0.7431448, 0.6691306, 0.7071068, 0.7071068, 0.6691306, 0.7431449,
			0.6293204, 0.7771460, 0.5877852, 0.8090170, 0.5446390, 0.8386706, 0.5000000, 0.8660254,
			0.4539905, 0.8910065, 0.4067366, 0.9135455, 0.3583679, 0.9335805, 0.3090170, 0.9510565,
			0.2588191, 0.9659258, 0.2079117, 0.9781476, 0.1564344, 0.9876884, 0.1045284, 0.9945219,
			0.5233597e-01, 0.9986295, 0.000000, 0.000000, 0.9945219, 0.1045285, 0.9781476, 0.2079117,
			0.9510565, 0.3090170, 0.9135454, 0.4067366, 0.8660254, 0.5000000, 0.8090170, 0.5877852,
			0.7431448, 0.6691306, 0.000000, 0.9781476, 0.2079117, 0.9135454, 0.4067366, 0.8090170,
			0.5877852, 0.6691306, 0.7431449, 0.5000000, 0.8660254, 0.3090170, 0.9510565, 0.1045284,
			0.9945219, 0.000000, 0.9510565, 0.3090170, 0.8090170, 0.5877852, 0.5877852, 0.8090170,
			0.3090170, 0.9510565, -0.4371139e-07, 1.000000, -0.3090170, 0.9510565, -0.5877852, 0.8090170,
			0.000000, 0.9135454, 0.4067366, 0.6691306, 0.7431449, 0.000000, 0.6691306, 0.7431449,
			-0.1045285, 0.9945219, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
		},
		wantiifac: []int{120, 4, 2, 4, 3, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 54,

		wantiwork: []float64{
			0.9995769, 0.9983082, 0.9961947, 0.9932383, 0.9894416, 0.9848077, 0.9793406, 0.9730449,
			0.9659258, 0.9579895, 0.9492427, 0.9396926, 0.9293475, 0.9182161, 0.9063078, 0.8936327,
			0.8802014, 0.8660254, 0.8511167, 0.8354878, 0.8191521, 0.8021232, 0.7844157, 0.7660444,
			0.7470251, 0.7273737, 0.7071068, 0.6862416, 0.6647958, 0.6427876, 0.6202354, 0.5971586,
			0.5735765, 0.5495090, 0.5249766, 0.5000000, 0.4746003, 0.4487992, 0.4226182, 0.3960797,
			0.3692062, 0.3420202, 0.3145447, 0.2868032, 0.2588191, 0.2306159, 0.2022175, 0.1736482,
			0.1449319, 0.1160929, 0.8715568e-01, 0.5814485e-01, 0.2908471e-01, -0.4371139e-07, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.9932383, 0.1160929, 0.9730449, 0.2306159,
			0.9396926, 0.3420201, 0.8936327, 0.4487992, 0.8354878, 0.5495090, 0.7660444, 0.6427876,
			0.6862416, 0.7273737, 0.5971586, 0.8021232, 0.5000000, 0.8660254, 0.3960797, 0.9182161,
			0.2868032, 0.9579895, 0.1736482, 0.9848077, 0.5814485e-01, 0.9983082, 0.000000, 0.9730449,
			0.2306159, 0.8936327, 0.4487992, 0.7660444, 0.6427876, 0.5971586, 0.8021232, 0.000000,
			0.8936327, 0.4487992, 0.5971586, 0.8021232, 0.1736482, 0.9848077, -0.2868032, 0.9579895,
			0.000000, 0.7660444, 0.6427876, 0.000000, 0.1736482, 0.9848077, 0.000000, 0.000000,
			0.000000, 0.000000,
		},
		wantiifac: []int{54, 4, 2, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 49,

		wantiwork: []float64{
			0.9994862, 0.9979454, 0.9953791, 0.9917900, 0.9871818, 0.9815592, 0.9749279, 0.9672949,
			0.9586679, 0.9490557, 0.9384684, 0.9269168, 0.9144126, 0.9009688, 0.8865993, 0.8713187,
			0.8551428, 0.8380881, 0.8201723, 0.8014136, 0.7818314, 0.7614459, 0.7402779, 0.7183493,
			0.6956825, 0.6723009, 0.6482283, 0.6234898, 0.5981105, 0.5721166, 0.5455348, 0.5183925,
			0.4907175, 0.4625383, 0.4338836, 0.4047833, 0.3752669, 0.3453650, 0.3151082, 0.2845275,
			0.2536545, 0.2225209, 0.1911586, 0.1595999, 0.1278771, 0.9602292e-01, 0.6407014e-01, 0.3205151e-01,
			-0.4371139e-07, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.9917900, 0.1278772, 0.9672949, 0.2536546, 0.9269168, 0.3752670,
			0.000000, 0.9672949, 0.2536546, 0.8713187, 0.4907176, 0.7183493, 0.6956826, 0.000000,
			0.9269168, 0.3752670, 0.7183493, 0.6956826, 0.4047833, 0.9144127, 0.000000, 0.8713187,
			0.4907176, 0.5183925, 0.8551428, 0.3205151e-01, 0.9994862, 0.000000, 0.8014136, 0.5981106,
			0.2845275, 0.9586679, -0.3453652, 0.9384683, 0.000000, 0.7183493, 0.6956826, 0.3205151e-01,
			0.9994862, -0.6723010, 0.7402779, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000,
		},
		wantiifac: []int{49, 2, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 32,

		wantiwork: []float64{
			0.9987954, 0.9951847, 0.9891765, 0.9807853, 0.9700313, 0.9569404, 0.9415441, 0.9238795,
			0.9039893, 0.8819212, 0.8577286, 0.8314696, 0.8032075, 0.7730104, 0.7409511, 0.7071068,
			0.6715589, 0.6343933, 0.5956993, 0.5555702, 0.5141027, 0.4713967, 0.4275551, 0.3826834,
			0.3368898, 0.2902846, 0.2429801, 0.1950902, 0.1467305, 0.9801713e-01, 0.4906765e-01, -0.4371139e-07,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.9807853, 0.1950903, 0.9238795, 0.3826835, 0.8314696, 0.5555702, 0.7071068, 0.7071068,
			0.5555702, 0.8314697, 0.3826834, 0.9238795, 0.1950902, 0.9807853, 0.000000, 0.000000,
			0.9238795, 0.3826835, 0.000000, 0.000000, 0.7071068, 0.7071068, 0.000000, 0.000000,
			0.3826834, 0.9238795, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
		},
		wantiifac: []int{32, 3, 2, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 25,

		wantiwork: []float64{
			0.9980267, 0.9921147, 0.9822872, 0.9685832, 0.9510565, 0.9297765, 0.9048271, 0.8763067,
			0.8443279, 0.8090170, 0.7705132, 0.7289686, 0.6845471, 0.6374239, 0.5877852, 0.5358267,
			0.4817536, 0.4257792, 0.3681245, 0.3090170, 0.2486898, 0.1873812, 0.1253331, 0.6279038e-01,
			-0.4371139e-07, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.9685832, 0.2486899, 0.8763067, 0.4817537, 0.000000, 0.8763067,
			0.4817537, 0.5358267, 0.8443279, 0.000000, 0.7289686, 0.6845471, 0.6279038e-01, 0.9980267,
			0.000000, 0.5358267, 0.8443279, -0.4257794, 0.9048270, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000,
		},
		wantiifac: []int{25, 2, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 4,

		wantiwork: []float64{
			0.9238795, 0.7071068, 0.3826834, -0.4371139e-07, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000,
		},
		wantiifac: []int{4, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 3,

		wantiwork: []float64{
			0.8660254, 0.5000000, -0.4371139e-07, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000,
		},
		wantiifac: []int{3, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 2,

		wantiwork: []float64{
			0.7071068, -0.4371139e-07, 0.000000, 0.000000, 0.000000, 0.000000,
		},
		wantiifac: []int{2, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
}

func series(n int) (x, y, xh []float64) {
	x = make([]float64, n)
	y = make([]float64, n)
	xh = make([]float64, n)
	for i := 0; i < n; i++ {
		x[i] = math.Sin(float64(i+1) * math.Sqrt2)
		y[i] = x[i]
		xh[i] = x[i]
	}
	return x, y, xh
}
// Copyright ©2018 The Gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// This is a translation and extension of the FFTPACK test
// functions by Paul N Swarztrauber, placed in the public
// domain at http://www.netlib.org/fftpack/.

package fftpack

import (
	"math"
	"math/cmplx"
	"reflect"
	"testing"

	"github.com/jingcheng-WU/gonum/cmplxs"
	"github.com/jingcheng-WU/gonum/floats"
	"github.com/jingcheng-WU/gonum/floats/scalar"
)

func TestRfft(t *testing.T) {
	t.Parallel()
	// Golden value cases where golden values have
	// been obtained from the original Fortran code.
	for _, test := range rfftTests {
		const tol = 1e-12
		testRfft(t, test.n, tol, test.wantiwork, test.wantiifac)
	}

	// General cases based purely on FFT behaviour.
	for n := 1; n < 500; n++ {
		const tol = 1e-9
		testRfft(t, n, tol, nil, nil)
	}
}

func testRfft(t *testing.T, n int, tol float64, wantiwork []float64, wantiifac []int) {
	// Compute the work and factor slices and compare to known values.
	work := make([]float64, 2*n)
	ifac := make([]int, 15)
	Rffti(n, work, ifac)
	var failed bool
	if wantiwork != nil && !floats.EqualApprox(work, wantiwork, 1e-6) {
		failed = true
		t.Errorf("unexpected work after call to rffti for n=%d", n)
	}
	if wantiifac != nil && !reflect.DeepEqual(ifac, wantiifac) {
		failed = true
		t.Errorf("unexpected ifac after call to rffti for n=%d", n)
	}
	if failed {
		return
	}

	// Construct a sequence with known a frequency spectrum and compare
	// the computed spectrum.
	modn := n % 2
	fn := float64(n)
	nm1 := n - 1
	x, y, xh := series(n)

	dt := 2 * math.Pi / fn
	ns2 := (n + 1) / 2
	if ns2 >= 2 {
		for k := 1; k < ns2; k++ { //eek
			var sum1, sum2 float64
			arg := float64(k) * dt
			for i := 0; i < n; i++ {
				arg1 := float64(i) * arg
				sum1 += x[i] * math.Cos(arg1)
				sum2 += x[i] * math.Sin(arg1)
			}
			y[2*k-1] = sum1
			y[2*k] = -sum2
		}
	}
	var sum1, sum2 float64
	for i := 0; i < nm1; i += 2 {
		sum1 += x[i]
		sum2 += x[i+1]
	}
	if modn == 1 {
		sum1 += x[n-1]
	}
	y[0] = sum1 + sum2
	if modn == 0 {
		y[n-1] = sum1 - sum2
	}

	want := naiveDFTreal(x)

	Rfftf(n, x, work, ifac)

	// Compare the result to a naive DFT implementation.
	if got := packCoeffs(x); !cmplxs.EqualApprox(got, want, tol) {
		t.Errorf("unexpected coefficients for n=%d: got:%f want:%f", n, got, want)
	}

	var rftf float64
	for i := 0; i < n; i++ {
		rftf = math.Max(rftf, math.Abs(x[i]-y[i]))
		x[i] = xh[i]
	}

	rftf /= fn
	if !scalar.EqualWithinAbsOrRel(rftf, 0, tol, tol) {
		t.Errorf("unexpected rftf value for n=%d: got:%f want:0", n, rftf)
	}

	// Construct a frequency spectrum and compare the computed sequence.
	for i := 0; i < n; i++ {
		sum := x[0] / 2
		arg := float64(i) * dt
		if ns2 >= 2 {
			for k := 1; k < ns2; k++ { //eek
				arg1 := float64(k) * arg
				sum += x[2*k-1]*math.Cos(arg1) - x[2*k]*math.Sin(arg1)
			}
		}
		if modn == 0 {
			// This is how it was written in FFTPACK.
			sum += 0.5 * math.Pow(-1, float64(i)) * x[n-1]
		}
		y[i] = 2 * sum
	}
	Rfftb(n, x, work, ifac)
	var rftb float64
	for i := 0; i < n; i++ {
		rftb = math.Max(rftb, math.Abs(x[i]-y[i]))
		x[i] = xh[i]
		y[i] = xh[i]
	}
	if !scalar.EqualWithinAbsOrRel(rftb, 0, tol, tol) {
		t.Errorf("unexpected rftb value for n=%d: got:%g want:0", n, rftb)
	}

	// Check that Rfftb and Rfftf are inverses.
	Rfftb(n, y, work, ifac)
	Rfftf(n, y, work, ifac)
	cf := 1.0 / fn
	var rftfb float64
	for i := 0; i < n; i++ {
		rftfb = math.Max(rftfb, math.Abs(cf*y[i]-x[i]))
	}
	if !scalar.EqualWithinAbsOrRel(rftfb, 0, tol, tol) {
		t.Errorf("unexpected rftfb value for n=%d: got:%f want:0", n, rftfb)
	}
}

// naiveDFTreal is the naive O(n^2) DFT implementation.
func naiveDFTreal(x []float64) (y []complex128) {
	y = make([]complex128, len(x))
	dt := -2 * math.Pi / float64(len(x))
	for i := range x {
		arg1 := float64(i) * dt
		for k, xv := range x {
			arg2 := float64(k) * arg1
			y[i] += complex(xv*math.Cos(arg2), xv*math.Sin(arg2))
		}
	}
	return y[:len(x)/2+1]
}

func packCoeffs(x []float64) []complex128 {
	y := make([]complex128, len(x)/2+1)
	y[0] = complex(x[0], 0)
	if len(x) < 2 {
		return y
	}
	if len(x)%2 == 1 {
		y[len(y)-1] = complex(x[len(x)-2], x[len(x)-1])
	} else {
		y[len(y)-1] = complex(x[len(x)-1], 0)
	}
	for i := 1; i < len(y)-1; i++ {
		y[i] = complex(x[2*i-1], x[2*i])
	}
	return y
}

var rfftTests = []struct {
	n int

	// The following two fields are added as there is no unit testing in
	// FFTPACK for RFFTI.
	//
	// wantiwork is obtained from the FFTPACK test.f with modification.
	// The W array is zeroed at each iteration and the first 2n elements
	// of W are printed after the call to RFFTI.
	wantiwork []float64
	// wantiifac is obtained from the FFTPACK rffti1.f with modification.
	// The IFAC array is zeroed at each iteration of test.f and the 15 elements
	// of IFAC are printed before RFFTI1 returns.
	wantiifac []int
}{
	{
		n: 120,

		wantiwork: []float64{
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.9986295, 0.5233596e-01, 0.9945219, 0.1045285, 0.9876884, 0.1564345, 0.9781476, 0.2079117,
			0.9659258, 0.2588190, 0.9510565, 0.3090170, 0.9335804, 0.3583679, 0.9135454, 0.4067366,
			0.8910065, 0.4539905, 0.8660254, 0.5000000, 0.8386706, 0.5446391, 0.8090170, 0.5877852,
			0.7771459, 0.6293204, 0.7431448, 0.6691306, 0.7071068, 0.7071068, 0.6691306, 0.7431449,
			0.6293204, 0.7771460, 0.5877852, 0.8090170, 0.5446390, 0.8386706, 0.5000000, 0.8660254,
			0.4539905, 0.8910065, 0.4067366, 0.9135455, 0.3583679, 0.9335805, 0.3090170, 0.9510565,
			0.2588191, 0.9659258, 0.2079117, 0.9781476, 0.1564344, 0.9876884, 0.1045284, 0.9945219,
			0.5233597e-01, 0.9986295, 0.000000, 0.000000, 0.9945219, 0.1045285, 0.9781476, 0.2079117,
			0.9510565, 0.3090170, 0.9135454, 0.4067366, 0.8660254, 0.5000000, 0.8090170, 0.5877852,
			0.7431448, 0.6691306, 0.000000, 0.9781476, 0.2079117, 0.9135454, 0.4067366, 0.8090170,
			0.5877852, 0.6691306, 0.7431449, 0.5000000, 0.8660254, 0.3090170, 0.9510565, 0.1045284,
			0.9945219, 0.000000, 0.9510565, 0.3090170, 0.8090170, 0.5877852, 0.5877852, 0.8090170,
			0.3090170, 0.9510565, -0.4371139e-07, 1.000000, -0.3090170, 0.9510565, -0.5877852, 0.8090170,
			0.000000, 0.9135454, 0.4067366, 0.6691306, 0.7431449, 0.000000, 0.6691306, 0.7431449,
			-0.1045285, 0.9945219, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
		},
		wantiifac: []int{120, 4, 2, 4, 3, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 54,

		wantiwork: []float64{
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.9932383, 0.1160929,
			0.9730449, 0.2306159, 0.9396926, 0.3420201, 0.8936327, 0.4487992, 0.8354878, 0.5495090,
			0.7660444, 0.6427876, 0.6862416, 0.7273737, 0.5971586, 0.8021232, 0.5000000, 0.8660254,
			0.3960797, 0.9182161, 0.2868032, 0.9579895, 0.1736482, 0.9848077, 0.5814485e-01, 0.9983082,
			0.000000, 0.9730449, 0.2306159, 0.8936327, 0.4487992, 0.7660444, 0.6427876, 0.5971586,
			0.8021232, 0.000000, 0.8936327, 0.4487992, 0.5971586, 0.8021232, 0.1736482, 0.9848077,
			-0.2868032, 0.9579895, 0.000000, 0.7660444, 0.6427876, 0.000000, 0.1736482, 0.9848077,
			0.000000, 0.000000, 0.000000, 0.000000,
		},
		wantiifac: []int{54, 4, 2, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 49,

		wantiwork: []float64{
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.9917900, 0.1278772, 0.9672949, 0.2536546, 0.9269168, 0.3752670, 0.000000,
			0.9672949, 0.2536546, 0.8713187, 0.4907176, 0.7183493, 0.6956826, 0.000000, 0.9269168,
			0.3752670, 0.7183493, 0.6956826, 0.4047833, 0.9144127, 0.000000, 0.8713187, 0.4907176,
			0.5183925, 0.8551428, 0.3205151e-01, 0.9994862, 0.000000, 0.8014136, 0.5981106, 0.2845275,
			0.9586679, -0.3453652, 0.9384683, 0.000000, 0.7183493, 0.6956826, 0.3205151e-01, 0.9994862,
			-0.6723010, 0.7402779, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000,
		},
		wantiifac: []int{49, 2, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 32,

		wantiwork: []float64{
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.9807853, 0.1950903, 0.9238795, 0.3826835, 0.8314696, 0.5555702, 0.7071068, 0.7071068,
			0.5555702, 0.8314697, 0.3826834, 0.9238795, 0.1950902, 0.9807853, 0.000000, 0.000000,
			0.9238795, 0.3826835, 0.000000, 0.000000, 0.7071068, 0.7071068, 0.000000, 0.000000,
			0.3826834, 0.9238795, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
		},
		wantiifac: []int{32, 3, 2, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 25,

		wantiwork: []float64{
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.968583, 0.248690, 0.876307, 0.481754, 0.00000, 0.876307, 0.481754,
			0.535827, 0.844328, 0.00000, 0.728969, 0.684547, 0.627904e-01, 0.998027, 0.00000,
			0.535827, 0.844328, -0.425779, 0.904827, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000,
		},
		wantiifac: []int{25, 2, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 4,

		wantiwork: []float64{
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
		},
		wantiifac: []int{4, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 3,

		wantiwork: []float64{
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
		},
		wantiifac: []int{3, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 2,

		wantiwork: []float64{
			0.000000, 0.000000, 0.000000, 0.000000,
		},
		wantiifac: []int{2, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
}

func TestCfft(t *testing.T) {
	t.Parallel()

	const tol = 1e-12

	// Golden value cases where golden values have
	// been obtained from the original Fortran code.
	for _, test := range cfftTests {
		testCfft(t, test.n, tol, test.wantiwork, test.wantiifac)
	}

	// General cases based purely on FFT behaviour.
	for n := 1; n < 500; n++ {
		testCfft(t, n, tol, nil, nil)
	}
}

func testCfft(t *testing.T, n int, tol float64, wantiwork []float64, wantiifac []int) {
	// Compute the work and factor slices and compare to known values.
	work := make([]float64, 4*n)
	ifac := make([]int, 15)
	Cffti(n, work, ifac)
	var failed bool
	if wantiwork != nil && !floats.EqualApprox(work, wantiwork, 1e-6) {
		failed = true
		t.Errorf("unexpected work after call to cffti for n=%d", n)
	}
	if wantiifac != nil && !reflect.DeepEqual(ifac, wantiifac) {
		failed = true
		t.Errorf("unexpected ifac after call to cffti for n=%d", n)
	}
	if failed {
		return
	}

	// Construct a sequence with known a frequency spectrum and compare
	// the computed spectrum.
	fn := float64(n)
	cn := complex(fn, 0)

	x, y1 := cmplxSeries(n)

	want := naiveDFT(x)

	cx := cmplxAsFloat(x)
	Cfftf(n, cx, work, ifac)
	x = floatAsCmplx(cx)

	// Compare the result to a naive DFT implementation.
	if !cmplxs.EqualApprox(x, want, tol*10) {
		t.Errorf("unexpected coefficients for n=%d: got:%f want:%f", n, x, want)
	}

	var cftf float64
	for i := 0; i < n; i++ {
		cftf = math.Max(cftf, cmplx.Abs(x[i]-y1[i]))
		x[i] /= cn
	}
	cftf /= fn

	if !scalar.EqualWithinAbsOrRel(cftf, 0, tol, tol) {
		t.Errorf("unexpected cftf value for n=%d: got:%f want:0", n, cftf)
	}

	// Construct a frequency spectrum and compare the computed sequence.
	y2 := updatedCmplxSeries(x)

	cx = cmplxAsFloat(x)
	Cfftb(n, cx, work, ifac)
	x = floatAsCmplx(cx)

	var cftb float64
	for i := 0; i < n; i++ {
		cftb = math.Max(cftb, cmplx.Abs(x[i]-y2[i]))
		x[i] = y2[i]
	}

	if !scalar.EqualWithinAbsOrRel(cftb, 0, tol, tol) {
		t.Errorf("unexpected cftb value for n=%d: got:%f want:0", n, cftb)
	}

	// Check that Cfftb and Cfftf are inverses.
	cx = cmplxAsFloat(x)
	Cfftf(n, cx, work, ifac)
	Cfftb(n, cx, work, ifac)
	x = floatAsCmplx(cx)

	var cftfb float64
	for i := 0; i < n; i++ {
		cftfb = math.Max(cftfb, cmplx.Abs(x[i]/cn-y2[i]))
	}

	if !scalar.EqualWithinAbsOrRel(cftfb, 0, tol, tol) {
		t.Errorf("unexpected cftfb value for n=%d: got:%f want:0", n, cftfb)
	}
}

// naiveDFT is the naive O(n^2) DFT implementation.
func naiveDFT(x []complex128) (y []complex128) {
	y = make([]complex128, len(x))
	dt := -2 * math.Pi / float64(len(x))
	for i := range x {
		arg1 := float64(i) * dt
		for k, xv := range x {
			arg2 := float64(k) * arg1
			y[i] += complex(math.Cos(arg2), math.Sin(arg2)) * xv
		}
	}
	return y
}
func cmplxSeries(n int) (x, y []complex128) {
	x = make([]complex128, n)
	for i := 0; i < n; i++ {
		x[i] = complex(math.Cos(math.Sqrt2*float64(i+1)), math.Sin(math.Sqrt2*float64((i+1)*(i+1))))
	}

	y = make([]complex128, n)
	dt := 2 * math.Pi / float64(n)
	for i := 0; i < n; i++ {
		arg1 := -float64(i) * dt
		for k := 0; k < n; k++ {
			arg2 := float64(k) * arg1
			y[i] += complex(math.Cos(arg2), math.Sin(arg2)) * x[k]
		}
	}
	return x, y
}

func updatedCmplxSeries(x []complex128) (y []complex128) {
	y = make([]complex128, len(x))
	dt := 2 * math.Pi / float64(len(x))
	for i := range x {
		arg1 := float64(i) * dt
		for k, xv := range x {
			arg2 := float64(k) * arg1
			y[i] += complex(math.Cos(arg2), math.Sin(arg2)) * xv
		}
	}
	return y
}

func cmplxAsFloat(c []complex128) []float64 {
	f := make([]float64, 2*len(c))
	for i, v := range c {
		f[2*i] = real(v)
		f[2*i+1] = imag(v)
	}
	return f
}

func floatAsCmplx(f []float64) []complex128 {
	c := make([]complex128, len(f)/2)
	for i := range c {
		c[i] = complex(f[2*i], f[2*i+1])
	}
	return c
}

var cfftTests = []struct {
	n int

	// The following two fields are added as there is no unit testing in
	// FFTPACK for RFFTI.
	//
	// wantiwork is obtained from the FFTPACK test.f with modification.
	// The W array is zeroed at each iteration and the first 4n elements
	// of W are printed after the call to RFFTI.
	wantiwork []float64
	// wantiifac is obtained from the FFTPACK rffti1.f with modification.
	// The IFAC array is zeroed at each iteration of test.f and the 15 elements
	// of IFAC are printed before RFFTI1 returns.
	wantiifac []int
}{
	{
		n: 120,

		wantiwork: []float64{
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			1.00000, 0.00000, 0.998630, 0.523360e-01, 0.994522, 0.104528, 0.987688, 0.156434,
			0.978148, 0.207912, 0.965926, 0.258819, 0.951057, 0.309017, 0.933580, 0.358368,
			0.913545, 0.406737, 0.891007, 0.453991, 0.866025, 0.500000, 0.838671, 0.544639,
			0.809017, 0.587785, 0.777146, 0.629320, 0.743145, 0.669131, 0.707107, 0.707107,
			0.669131, 0.743145, 0.629320, 0.777146, 0.587785, 0.809017, 0.544639, 0.838671,
			0.500000, 0.866025, 0.453991, 0.891007, 0.406737, 0.913545, 0.358368, 0.933580,
			0.309017, 0.951057, 0.258819, 0.965926, 0.207912, 0.978148, 0.156434, 0.987688,
			0.104528, 0.994522, 0.523360e-01, 0.998630, -0.437114e-07, 1.00000, -0.523361e-01, 0.998630,
			-0.104529, 0.994522, -0.156434, 0.987688, -0.207912, 0.978148, -0.258819, 0.965926,
			-0.309017, 0.951056, -0.358368, 0.933580, -0.406737, 0.913545, -0.453991, 0.891006,
			-0.500000, 0.866025, -0.544639, 0.838671, -0.587785, 0.809017, -0.629321, 0.777146,
			-0.669131, 0.743145, -0.707107, 0.707107, -0.743145, 0.669130, -0.777146, 0.629320,
			-0.809017, 0.587785, -0.838671, 0.544639, -0.866025, 0.500000, -0.891007, 0.453990,
			-0.913545, 0.406737, -0.933580, 0.358368, -0.951057, 0.309017, -0.965926, 0.258819,
			-0.978148, 0.207912, -0.987688, 0.156434, -0.994522, 0.104528, -0.998630, 0.523358e-01,
			1.00000, 0.00000, 0.994522, 0.104528, 0.978148, 0.207912, 0.951057, 0.309017,
			0.913545, 0.406737, 0.866025, 0.500000, 0.809017, 0.587785, 0.743145, 0.669131,
			0.669131, 0.743145, 0.587785, 0.809017, 0.500000, 0.866025, 0.406737, 0.913545,
			0.309017, 0.951057, 0.207912, 0.978148, 0.104528, 0.994522, -0.437114e-07, 1.00000,
			-0.104529, 0.994522, -0.207912, 0.978148, -0.309017, 0.951056, -0.406737, 0.913545,
			1.00000, 0.00000, 0.978148, 0.207912, 0.913545, 0.406737, 0.809017, 0.587785,
			0.669131, 0.743145, 0.500000, 0.866025, 0.309017, 0.951057, 0.104528, 0.994522,
			-0.104529, 0.994522, -0.309017, 0.951056, -0.500000, 0.866025, -0.669131, 0.743145,
			-0.809017, 0.587785, -0.913545, 0.406737, -0.978148, 0.207912, -1.00000, -0.874228e-07,
			-0.978148, -0.207912, -0.913545, -0.406737, -0.809017, -0.587785, -0.669131, -0.743145,
			1.00000, 0.00000, 0.951057, 0.309017, 0.809017, 0.587785, 0.587785, 0.809017,
			0.309017, 0.951057, 1.00000, 0.00000, 0.809017, 0.587785, 0.309017, 0.951057,
			-0.309017, 0.951056, -0.809017, 0.587785, 1.00000, 0.00000, 0.587785, 0.809017,
			-0.309017, 0.951056, -0.951057, 0.309017, -0.809017, -0.587785, 1.00000, 0.00000,
			1.00000, 0.00000, 1.00000, 0.00000, 1.00000, 0.00000, 0.309017, -0.951056,
		},
		wantiifac: []int{120, 4, 2, 3, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 54,

		wantiwork: []float64{
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 1.00000, 0.00000, 0.993238, 0.116093,
			0.973045, 0.230616, 0.939693, 0.342020, 0.893633, 0.448799, 0.835488, 0.549509,
			0.766044, 0.642788, 0.686242, 0.727374, 0.597159, 0.802123, 0.500000, 0.866025,
			0.396080, 0.918216, 0.286803, 0.957990, 0.173648, 0.984808, 0.581449e-01, 0.998308,
			-0.581448e-01, 0.998308, -0.173648, 0.984808, -0.286803, 0.957990, -0.396080, 0.918216,
			-0.500000, 0.866025, -0.597159, 0.802123, -0.686242, 0.727374, -0.766044, 0.642788,
			-0.835488, 0.549509, -0.893633, 0.448799, -0.939693, 0.342020, -0.973045, 0.230616,
			-0.993238, 0.116093, 1.00000, 0.00000, 0.973045, 0.230616, 0.893633, 0.448799,
			0.766044, 0.642788, 0.597159, 0.802123, 0.396080, 0.918216, 0.173648, 0.984808,
			-0.581448e-01, 0.998308, -0.286803, 0.957990, 1.00000, 0.00000, 0.893633, 0.448799,
			0.597159, 0.802123, 0.173648, 0.984808, -0.286803, 0.957990, -0.686242, 0.727374,
			-0.939693, 0.342020, -0.993238, -0.116093, -0.835488, -0.549509, 1.00000, 0.00000,
			0.766044, 0.642788, 0.173648, 0.984808, 1.00000, 0.00000, 0.173648, 0.984808,
			-0.939693, 0.342020, 1.00000, 0.00000, 1.00000, 0.00000, -0.500000, -0.866025,
		},
		wantiifac: []int{54, 4, 2, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 49,

		wantiwork: []float64{
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.623490, 0.781832, 0.991790, 0.127877, 0.967295, 0.253655,
			0.926917, 0.375267, 0.871319, 0.490718, 0.801414, 0.598111, 0.718349, 0.695683,
			-0.222521, 0.974928, 0.967295, 0.253655, 0.871319, 0.490718, 0.718349, 0.695683,
			0.518393, 0.855143, 0.284527, 0.958668, 0.320515e-01, 0.999486, -0.900969, 0.433884,
			0.926917, 0.375267, 0.718349, 0.695683, 0.404783, 0.914413, 0.320515e-01, 0.999486,
			-0.345365, 0.938468, -0.672301, 0.740278, -0.900969, -0.433884, 0.871319, 0.490718,
			0.518393, 0.855143, 0.320515e-01, 0.999486, -0.462538, 0.886599, -0.838088, 0.545535,
			-0.997945, 0.640701e-01, -0.222521, -0.974928, 0.801414, 0.598111, 0.284527, 0.958668,
			-0.345365, 0.938468, -0.838088, 0.545535, -0.997945, -0.640705e-01, -0.761446, -0.648229,
			0.623490, -0.781831, 0.718349, 0.695683, 0.320515e-01, 0.999486, -0.672301, 0.740278,
			-0.997945, 0.640701e-01, -0.761446, -0.648228, -0.960227e-01, -0.995379, 0.623490, 0.781832,
			-0.222521, 0.974928, -0.900969, 0.433884, -0.900969, -0.433884, -0.222521, -0.974928,
			0.623490, -0.781831, 0.623490, -0.781831,
		},
		wantiifac: []int{49, 2, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 32,

		wantiwork: []float64{
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			1.00000, 0.00000, 0.980785, 0.195090, 0.923880, 0.382683, 0.831470, 0.555570,
			0.707107, 0.707107, 0.555570, 0.831470, 0.382683, 0.923880, 0.195090, 0.980785,
			-0.437114e-07, 1.00000, -0.195090, 0.980785, -0.382684, 0.923880, -0.555570, 0.831470,
			-0.707107, 0.707107, -0.831470, 0.555570, -0.923880, 0.382683, -0.980785, 0.195090,
			1.00000, 0.00000, 0.923880, 0.382683, 0.707107, 0.707107, 0.382683, 0.923880,
			1.00000, 0.00000, 0.707107, 0.707107, -0.437114e-07, 1.00000, -0.707107, 0.707107,
			1.00000, 0.00000, 0.382683, 0.923880, -0.707107, 0.707107, -0.923880, -0.382683,
			1.00000, 0.00000, 1.00000, 0.00000, 1.00000, 0.00000, 0.119249e-07, -1.00000,
		},
		wantiifac: []int{32, 3, 2, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 25,

		wantiwork: []float64{
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			0.00000, 0.00000, 1.00000, 0.00000, 0.968583, 0.248690, 0.876307, 0.481754,
			0.728969, 0.684547, 0.535827, 0.844328, 1.00000, 0.00000, 0.876307, 0.481754,
			0.535827, 0.844328, 0.627904e-01, 0.998027, -0.425779, 0.904827, 1.00000, 0.00000,
			0.728969, 0.684547, 0.627904e-01, 0.998027, -0.637424, 0.770513, -0.992115, 0.125333,
			1.00000, 0.00000, 0.535827, 0.844328, -0.425779, 0.904827, -0.992115, 0.125333,
			-0.637424, -0.770513, 1.00000, 0.00000, 1.00000, 0.00000, 1.00000, 0.00000,
			1.00000, 0.00000, 0.309017, -0.951056,
		},
		wantiifac: []int{25, 2, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 4,

		wantiwork: []float64{
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000,
			1.00000, 0.00000, 1.00000, 0.00000, 1.00000, 0.00000, 0.119249e-07, -1.00000,
		},
		wantiifac: []int{4, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 3,

		wantiwork: []float64{
			0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 0.00000, 1.00000, 0.00000,
			1.00000, 0.00000, -0.500000, -0.866025,
		},
		wantiifac: []int{3, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 2,

		wantiwork: []float64{
			0.00000, 0.00000, 0.00000, 0.00000, 1.00000, 0.00000, -1.00000, -0.874228e-07,
		},
		wantiifac: []int{2, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
}

func TestSint(t *testing.T) {
	t.Parallel()
	const tol = 1e-12
	for _, test := range sintTests {
		// Compute the work and factor slices and compare to known values.
		work := make([]float64, 5*(test.n)/2)
		ifac := make([]int, 15)
		Sinti(test.n-1, work, ifac)
		var failed bool
		if !floats.EqualApprox(work, test.wantiwork, 1e-6) {
			failed = true
			t.Errorf("unexpected work after call to sinti for n=%d", test.n)
		}
		if !reflect.DeepEqual(ifac, test.wantiifac) {
			failed = true
			t.Errorf("unexpected ifac after call to sinti for n=%d", test.n)
		}
		if failed {
			continue
		}

		// Construct a sequence with known a frequency spectrum and compare
		// the computed spectrum.
		fn := float64(test.n)
		x, _, xh := series(test.n - 1)
		y := make([]float64, test.n-1)

		dt := math.Pi / fn
		for i := 0; i < test.n-1; i++ {
			arg1 := float64(i+1) * dt
			for k := 0; k < test.n-1; k++ { //eek
				y[i] += x[k] * math.Sin(float64(k+1)*arg1)
			}
			y[i] *= 2
		}

		Sint(test.n-1, x, work, ifac)

		cf := 0.5 / fn
		var sintt float64
		for i := 0; i < test.n-1; i++ {
			sintt = math.Max(sintt, math.Abs(x[i]-y[i]))
			x[i] = xh[i]
			y[i] = x[i]
		}
		sintt *= cf
		if !scalar.EqualWithinAbsOrRel(sintt, 0, tol, tol) {
			t.Errorf("unexpected sintt value for n=%d: got:%f want:0", test.n, sintt)
		}

		// Check that the transform is its own inverse.
		Sint(test.n-1, x, work, ifac)
		Sint(test.n-1, x, work, ifac)

		var sintfb float64
		for i := 0; i < test.n-1; i++ {
			sintfb = math.Max(sintfb, math.Abs(cf*x[i]-y[i]))
		}
		if !scalar.EqualWithinAbsOrRel(sintfb, 0, tol, tol) {
			t.Errorf("unexpected sintfb value for n=%d: got:%f want:0", test.n, sintfb)
		}
	}
}

var sintTests = []struct {
	n int

	// The following two fields are added as there is no unit testing in
	// FFTPACK for SINTI.
	//
	// wantiwork is obtained from the FFTPACK test.f with modification.
	// The W array is zeroed at each iteration and the first 2.5n elements
	// of W are printed after the call to RFFTI.
	wantiwork []float64
	// wantiifac is obtained from the FFTPACK sint.f with modification.
	// The IFAC array is zeroed at each iteration of test.f and the 15 elements
	// of IFAC are printed before RFFTI returns.
	wantiifac []int
}{
	{
		n: 120,

		wantiwork: []float64{
			0.5235390e-01, 0.1046719, 0.1569182, 0.2090569, 0.2610524, 0.3128690, 0.3644710, 0.4158234,
			0.4668908, 0.5176381, 0.5680307, 0.6180340, 0.6676137, 0.7167359, 0.7653669, 0.8134733,
			0.8610222, 0.9079810, 0.9543176, 1.000000, 1.044997, 1.089278, 1.132812, 1.175570,
			1.217523, 1.258641, 1.298896, 1.338261, 1.376709, 1.414214, 1.450749, 1.486290,
			1.520812, 1.554292, 1.586707, 1.618034, 1.648252, 1.677341, 1.705280, 1.732051,
			1.757634, 1.782013, 1.805171, 1.827091, 1.847759, 1.867161, 1.885283, 1.902113,
			1.917639, 1.931852, 1.944740, 1.956295, 1.966510, 1.975377, 1.982890, 1.989044,
			1.993835, 1.997259, 1.999315, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.9986295, 0.5233596e-01, 0.9945219, 0.1045285, 0.9876884,
			0.1564345, 0.9781476, 0.2079117, 0.9659258, 0.2588190, 0.9510565, 0.3090170, 0.9335804,
			0.3583679, 0.9135454, 0.4067366, 0.8910065, 0.4539905, 0.8660254, 0.5000000, 0.8386706,
			0.5446391, 0.8090170, 0.5877852, 0.7771459, 0.6293204, 0.7431448, 0.6691306, 0.7071068,
			0.7071068, 0.6691306, 0.7431449, 0.6293204, 0.7771460, 0.5877852, 0.8090170, 0.5446390,
			0.8386706, 0.5000000, 0.8660254, 0.4539905, 0.8910065, 0.4067366, 0.9135455, 0.3583679,
			0.9335805, 0.3090170, 0.9510565, 0.2588191, 0.9659258, 0.2079117, 0.9781476, 0.1564344,
			0.9876884, 0.1045284, 0.9945219, 0.5233597e-01, 0.9986295, 0.000000, 0.000000, 0.9945219,
			0.1045285, 0.9781476, 0.2079117, 0.9510565, 0.3090170, 0.9135454, 0.4067366, 0.8660254,
			0.5000000, 0.8090170, 0.5877852, 0.7431448, 0.6691306, 0.000000, 0.9781476, 0.2079117,
			0.9135454, 0.4067366, 0.8090170, 0.5877852, 0.6691306, 0.7431449, 0.5000000, 0.8660254,
			0.3090170, 0.9510565, 0.1045284, 0.9945219, 0.000000, 0.9510565, 0.3090170, 0.8090170,
			0.5877852, 0.5877852, 0.8090170, 0.3090170, 0.9510565, -0.4371139e-07, 1.000000, -0.3090170,
			0.9510565, -0.5877852, 0.8090170, 0.000000, 0.9135454, 0.4067366, 0.6691306, 0.7431449,
			0.000000, 0.6691306, 0.7431449, -0.1045285, 0.9945219, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.1681558e-42,
		},
		wantiifac: []int{120, 4, 2, 4, 3, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 54,

		wantiwork: []float64{
			0.1162897, 0.2321858, 0.3472964, 0.4612317, 0.5736065, 0.6840402, 0.7921596, 0.8975984,
			1.000000, 1.099018, 1.194317, 1.285575, 1.372483, 1.454747, 1.532089, 1.604246,
			1.670976, 1.732051, 1.787265, 1.836432, 1.879385, 1.915979, 1.946090, 1.969615,
			1.986477, 1.996616, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.9932383, 0.1160929, 0.9730449, 0.2306159, 0.9396926, 0.3420201, 0.8936327, 0.4487992,
			0.8354878, 0.5495090, 0.7660444, 0.6427876, 0.6862416, 0.7273737, 0.5971586, 0.8021232,
			0.5000000, 0.8660254, 0.3960797, 0.9182161, 0.2868032, 0.9579895, 0.1736482, 0.9848077,
			0.5814485e-01, 0.9983082, 0.000000, 0.9730449, 0.2306159, 0.8936327, 0.4487992, 0.7660444,
			0.6427876, 0.5971586, 0.8021232, 0.000000, 0.8936327, 0.4487992, 0.5971586, 0.8021232,
			0.1736482, 0.9848077, -0.2868032, 0.9579895, 0.000000, 0.7660444, 0.6427876, 0.000000,
			0.1736482, 0.9848077, 0.000000, 0.000000, 0.000000, 0.000000, 0.7567012e-43,
		},
		wantiifac: []int{54, 4, 2, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 49,

		wantiwork: []float64{
			0.1281404, 0.2557543, 0.3823173, 0.5073092, 0.6302165, 0.7505341, 0.8677675, 0.9814351,
			1.091070, 1.196221, 1.296457, 1.391365, 1.480556, 1.563663, 1.640345, 1.710286,
			1.773199, 1.828825, 1.876937, 1.917336, 1.949856, 1.974364, 1.990758, 1.998972,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.9917900, 0.1278772, 0.9672949, 0.2536546, 0.9269168, 0.3752670, 0.000000,
			0.9672949, 0.2536546, 0.8713187, 0.4907176, 0.7183493, 0.6956826, 0.000000, 0.9269168,
			0.3752670, 0.7183493, 0.6956826, 0.4047833, 0.9144127, 0.000000, 0.8713187, 0.4907176,
			0.5183925, 0.8551428, 0.3205151e-01, 0.9994862, 0.000000, 0.8014136, 0.5981106, 0.2845275,
			0.9586679, -0.3453652, 0.9384683, 0.000000, 0.7183493, 0.6956826, 0.3205151e-01, 0.9994862,
			-0.6723010, 0.7402779, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000,
		},
		wantiifac: []int{49, 2, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 32,

		wantiwork: []float64{
			0.1960343, 0.3901806, 0.5805693, 0.7653669, 0.9427935, 1.111140, 1.268787, 1.414214,
			1.546021, 1.662939, 1.763843, 1.847759, 1.913881, 1.961571, 1.990369, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.9807853,
			0.1950903, 0.9238795, 0.3826835, 0.8314696, 0.5555702, 0.7071068, 0.7071068, 0.5555702,
			0.8314697, 0.3826834, 0.9238795, 0.1950902, 0.9807853, 0.000000, 0.000000, 0.9238795,
			0.3826835, 0.000000, 0.000000, 0.7071068, 0.7071068, 0.000000, 0.000000, 0.3826834,
			0.9238795, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.4484155e-43,
		},
		wantiifac: []int{32, 3, 2, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 25,

		wantiwork: []float64{
			0.2506665, 0.4973798, 0.7362491, 0.9635074, 1.175570, 1.369094, 1.541027, 1.688656,
			1.809654, 1.902113, 1.964575, 1.996053, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.9685832, 0.2486899, 0.8763067,
			0.4817537, 0.000000, 0.8763067, 0.4817537, 0.5358267, 0.8443279, 0.000000, 0.7289686,
			0.6845471, 0.6279038e-01, 0.9980267, 0.000000, 0.5358267, 0.8443279, -0.4257794, 0.9048270,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
		},
		wantiifac: []int{25, 2, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 4,

		wantiwork: []float64{
			1.414214, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000,
		},
		wantiifac: []int{4, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 3,

		wantiwork: []float64{
			1.732051, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
		},
		wantiifac: []int{3, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 2,

		wantiwork: []float64{
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
		},
		wantiifac: []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
}

func TestCost(t *testing.T) {
	t.Parallel()
	const tol = 1e-12
	for _, test := range costTests {
		// Compute the work and factor slices and compare to known values.
		work := make([]float64, 3*(test.n+1))
		ifac := make([]int, 15)
		Costi(test.n+1, work, ifac)
		var failed bool
		if !floats.EqualApprox(work, test.wantiwork, 1e-6) {
			failed = true
			t.Errorf("unexpected work after call to costi for n=%d", test.n)
		}
		if !reflect.DeepEqual(ifac, test.wantiifac) {
			failed = true
			t.Errorf("unexpected ifac after call to costi for n=%d", test.n)
		}
		if failed {
			continue
		}

		// Construct a sequence with known a frequency spectrum and compare
		// the computed spectrum.
		fn := float64(test.n)
		x, _, xh := series(test.n + 1)
		y := make([]float64, test.n+1)

		dt := math.Pi / fn
		for i := 0; i < test.n+1; i++ {
			y[i] = 0.5 * (x[0] + math.Pow(-1, float64(i))*x[test.n])
			arg1 := float64(i) * dt
			for k := 1; k < test.n; k++ { //eek
				y[i] += x[k] * math.Cos(float64(k)*arg1)
			}
			y[i] *= 2
		}

		Cost(test.n+1, x, work, ifac)

		cf := 0.5 / fn
		var costt float64
		for i := 0; i < test.n; i++ {
			costt = math.Max(costt, math.Abs(x[i]-y[i]))
			x[i] = xh[i]
			y[i] = x[i]
		}
		costt *= cf
		if !scalar.EqualWithinAbsOrRel(costt, 0, tol, tol) {
			t.Errorf("unexpected costt value for n=%d: got:%f want:0", test.n, costt)
		}

		// Check that the transform is its own inverse.
		Cost(test.n+1, x, work, ifac)
		Cost(test.n+1, x, work, ifac)

		var costfb float64
		for i := 0; i < test.n-1; i++ {
			costfb = math.Max(costfb, math.Abs(cf*x[i]-y[i]))
		}
		if !scalar.EqualWithinAbsOrRel(costfb, 0, tol, tol) {
			t.Errorf("unexpected costfb value for n=%d: got:%f want:0", test.n, costfb)
		}
	}
}

var costTests = []struct {
	n int

	// The following two fields are added as there is no unit testing in
	// FFTPACK for SINTI.
	//
	// wantiwork is obtained from the FFTPACK test.f with modification.
	// The W array is zeroed at each iteration and the first 3n elements
	// of W are printed after the call to RFFTI.
	wantiwork []float64
	// wantiifac is obtained from the FFTPACK sint.f with modification.
	// The IFAC array is zeroed at each iteration of test.f and the 15 elements
	// of IFAC are printed before RFFTI returns.
	wantiifac []int
}{
	{
		n: 120,

		wantiwork: []float64{
			0.000000, 0.5235390e-01, 0.1046719, 0.1569182, 0.2090569, 0.2610524, 0.3128690, 0.3644710,
			0.4158234, 0.4668908, 0.5176381, 0.5680307, 0.6180340, 0.6676137, 0.7167359, 0.7653669,
			0.8134733, 0.8610222, 0.9079810, 0.9543176, 1.000000, 1.044997, 1.089278, 1.132812,
			1.175570, 1.217523, 1.258641, 1.298896, 1.338261, 1.376709, 1.414214, 1.450749,
			1.486290, 1.520812, 1.554292, 1.586707, 1.618034, 1.648252, 1.677341, 1.705280,
			1.732051, 1.757634, 1.782013, 1.805171, 1.827091, 1.847759, 1.867161, 1.885283,
			1.902113, 1.917639, 1.931852, 1.944740, 1.956295, 1.966510, 1.975377, 1.982890,
			1.989044, 1.993835, 1.997259, 1.999315, 0.000000, 0.5235375e-01, 0.1046719, 0.1569182,
			0.2090568, 0.2610523, 0.3128687, 0.3644710, 0.4158233, 0.4668906, 0.5176381, 0.5680307,
			0.6180339, 0.6676136, 0.7167357, 0.7653669, 0.8134732, 0.8610221, 0.9079810, 0.9543175,
			1.000000, 1.044997, 1.089278, 1.132812, 1.175570, 1.217523, 1.258641, 1.298896,
			1.338261, 1.376709, 1.414214, 1.450749, 1.486290, 1.520812, 1.554292, 1.586707,
			1.618034, 1.648252, 1.677341, 1.705280, 1.732051, 1.757634, 1.782013, 1.805171,
			1.827091, 1.847759, 1.867161, 1.885283, 1.902113, 1.917639, 1.931852, 1.944740,
			1.956295, 1.966510, 1.975377, 1.982890, 1.989044, 1.993835, 1.997259, 1.999315,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.9986295, 0.5233596e-01, 0.9945219, 0.1045285, 0.9876884, 0.1564345, 0.9781476,
			0.2079117, 0.9659258, 0.2588190, 0.9510565, 0.3090170, 0.9335804, 0.3583679, 0.9135454,
			0.4067366, 0.8910065, 0.4539905, 0.8660254, 0.5000000, 0.8386706, 0.5446391, 0.8090170,
			0.5877852, 0.7771459, 0.6293204, 0.7431448, 0.6691306, 0.7071068, 0.7071068, 0.6691306,
			0.7431449, 0.6293204, 0.7771460, 0.5877852, 0.8090170, 0.5446390, 0.8386706, 0.5000000,
			0.8660254, 0.4539905, 0.8910065, 0.4067366, 0.9135455, 0.3583679, 0.9335805, 0.3090170,
			0.9510565, 0.2588191, 0.9659258, 0.2079117, 0.9781476, 0.1564344, 0.9876884, 0.1045284,
			0.9945219, 0.5233597e-01, 0.9986295, 0.000000, 0.000000, 0.9945219, 0.1045285, 0.9781476,
			0.2079117, 0.9510565, 0.3090170, 0.9135454, 0.4067366, 0.8660254, 0.5000000, 0.8090170,
			0.5877852, 0.7431448, 0.6691306, 0.000000, 0.9781476, 0.2079117, 0.9135454, 0.4067366,
			0.8090170, 0.5877852, 0.6691306, 0.7431449, 0.5000000, 0.8660254, 0.3090170, 0.9510565,
			0.1045284, 0.9945219, 0.000000, 0.9510565, 0.3090170, 0.8090170, 0.5877852, 0.5877852,
			0.8090170, 0.3090170, 0.9510565, -0.4371139e-07, 1.000000, -0.3090170, 0.9510565, -0.5877852,
			0.8090170, 0.000000, 0.9135454, 0.4067366, 0.6691306, 0.7431449, 0.000000, 0.6691306,
			0.7431449, -0.1045285, 0.9945219, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.1681558e-42, 0.5605194e-44,
		},
		wantiifac: []int{120, 4, 2, 4, 3, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 54,

		wantiwork: []float64{
			0.000000, 0.1162897, 0.2321858, 0.3472964, 0.4612317, 0.5736065, 0.6840402, 0.7921596,
			0.8975984, 1.000000, 1.099018, 1.194317, 1.285575, 1.372483, 1.454747, 1.532089,
			1.604246, 1.670976, 1.732051, 1.787265, 1.836432, 1.879385, 1.915979, 1.946090,
			1.969615, 1.986477, 1.996616, 0.000000, 0.1162897, 0.2321858, 0.3472964, 0.4612317,
			0.5736064, 0.6840403, 0.7921594, 0.8975984, 1.000000, 1.099018, 1.194317, 1.285575,
			1.372483, 1.454747, 1.532089, 1.604246, 1.670976, 1.732051, 1.787265, 1.836432,
			1.879385, 1.915979, 1.946090, 1.969615, 1.986477, 1.996616, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.9932383, 0.1160929, 0.9730449,
			0.2306159, 0.9396926, 0.3420201, 0.8936327, 0.4487992, 0.8354878, 0.5495090, 0.7660444,
			0.6427876, 0.6862416, 0.7273737, 0.5971586, 0.8021232, 0.5000000, 0.8660254, 0.3960797,
			0.9182161, 0.2868032, 0.9579895, 0.1736482, 0.9848077, 0.5814485e-01, 0.9983082, 0.000000,
			0.9730449, 0.2306159, 0.8936327, 0.4487992, 0.7660444, 0.6427876, 0.5971586, 0.8021232,
			0.000000, 0.8936327, 0.4487992, 0.5971586, 0.8021232, 0.1736482, 0.9848077, -0.2868032,
			0.9579895, 0.000000, 0.7660444, 0.6427876, 0.000000, 0.1736482, 0.9848077, 0.000000,
			0.000000, 0.000000, 0.000000, 0.7567012e-43, 0.5605194e-44,
		},
		wantiifac: []int{54, 4, 2, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 49,

		wantiwork: []float64{
			0.000000, 0.1281404, 0.2557543, 0.3823173, 0.5073092, 0.6302165, 0.7505341, 0.8677675,
			0.9814351, 1.091070, 1.196221, 1.296457, 1.391365, 1.480556, 1.563663, 1.640345,
			1.710286, 1.773199, 1.828825, 1.876937, 1.917336, 1.949856, 1.974364, 1.990758,
			1.998972, 0.6410302e-01, 0.1920458, 0.3191997, 0.4450417, 0.5690550, 0.6907300, 0.8095666,
			0.9250766, 1.036785, 1.144233, 1.246980, 1.344602, 1.436699, 1.522892, 1.602827,
			1.676176, 1.742637, 1.801938, 1.853834, 1.898111, 1.934590, 1.963118, 1.983580,
			1.995891, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.9917900, 0.1278772, 0.9672949, 0.2536546, 0.9269168,
			0.3752670, 0.000000, 0.9672949, 0.2536546, 0.8713187, 0.4907176, 0.7183493, 0.6956826,
			0.000000, 0.9269168, 0.3752670, 0.7183493, 0.6956826, 0.4047833, 0.9144127, 0.000000,
			0.8713187, 0.4907176, 0.5183925, 0.8551428, 0.3205151e-01, 0.9994862, 0.000000, 0.8014136,
			0.5981106, 0.2845275, 0.9586679, -0.3453652, 0.9384683, 0.000000, 0.7183493, 0.6956826,
			0.3205151e-01, 0.9994862, -0.6723010, 0.7402779, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.6866362e-43, 0.2802597e-44,
		},
		wantiifac: []int{49, 2, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 32,

		wantiwork: []float64{
			0.000000, 0.1960343, 0.3901806, 0.5805693, 0.7653669, 0.9427935, 1.111140, 1.268787,
			1.414214, 1.546021, 1.662939, 1.763843, 1.847759, 1.913881, 1.961571, 1.990369,
			0.000000, 0.1960343, 0.3901805, 0.5805693, 0.7653669, 0.9427933, 1.111140, 1.268787,
			1.414214, 1.546021, 1.662939, 1.763842, 1.847759, 1.913881, 1.961571, 1.990369,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.9807853, 0.1950903, 0.9238795, 0.3826835, 0.8314696, 0.5555702, 0.7071068,
			0.7071068, 0.5555702, 0.8314697, 0.3826834, 0.9238795, 0.1950902, 0.9807853, 0.000000,
			0.000000, 0.9238795, 0.3826835, 0.000000, 0.000000, 0.7071068, 0.7071068, 0.000000,
			0.000000, 0.3826834, 0.9238795, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.4484155e-43, 0.4203895e-44,
		},
		wantiifac: []int{32, 3, 2, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 25,

		wantiwork: []float64{
			0.000000, 0.2506665, 0.4973798, 0.7362491, 0.9635074, 1.175570, 1.369094, 1.541027,
			1.688656, 1.809654, 1.902113, 1.964575, 1.996053, 0.1255808, 0.3747624, 0.6180339,
			0.8515584, 1.071653, 1.274848, 1.457937, 1.618034, 1.752613, 1.859553, 1.937166,
			1.984229, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.9685832, 0.2486899, 0.8763067, 0.4817537, 0.000000,
			0.8763067, 0.4817537, 0.5358267, 0.8443279, 0.000000, 0.7289686, 0.6845471, 0.6279038e-01,
			0.9980267, 0.000000, 0.5358267, 0.8443279, -0.4257794, 0.9048270, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.3503246e-43, 0.2802597e-44,
		},
		wantiifac: []int{25, 2, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 4,

		wantiwork: []float64{
			0.000000, 1.414214, 0.000000, 1.414214, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.5605194e-44, 0.1401298e-44,
		},
		wantiifac: []int{4, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 3,

		wantiwork: []float64{
			0.000000, 1.732051, 1.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.4203895e-44, 0.1401298e-44,
		},
		wantiifac: []int{3, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 2,

		wantiwork: []float64{
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000,
		},
		wantiifac: []int{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
}

func TestCosq(t *testing.T) {
	t.Parallel()
	const tol = 1e-12
	for _, test := range sincosqTests {
		// Compute the work and factor slices and compare to known values.
		work := make([]float64, 3*test.n)
		ifac := make([]int, 15)
		Cosqi(test.n, work, ifac)
		var failed bool
		if !floats.EqualApprox(work, test.wantiwork, 1e-6) {
			failed = true
			t.Errorf("unexpected work after call to cosqi for n=%d", test.n)
			t.Logf("\n%v\n%v", work, test.wantiwork)
		}
		if !reflect.DeepEqual(ifac, test.wantiifac) {
			failed = true
			t.Errorf("unexpected ifac after call to cosqi for n=%d", test.n)
		}
		if failed {
			continue
		}

		// Construct a sequence with known a frequency spectrum and compare
		// the computed spectrum.
		fn := float64(test.n)
		x := make([]float64, test.n)
		y, _, xh := series(test.n)

		dt := math.Pi / (2 * fn)
		for i := 0; i < test.n; i++ {
			arg := float64(i) * dt
			for k := 0; k < test.n; k++ {
				x[i] += y[k] * math.Cos(float64(2*k+1)*arg)
			}
			x[i] *= 4
		}

		Cosqb(test.n, y, work, ifac)

		cf := 0.25 / fn
		var cosqbt float64
		for i := 0; i < test.n; i++ {
			cosqbt = math.Max(cosqbt, math.Abs(x[i]-y[i]))
			x[i] = xh[i]
		}
		cosqbt *= cf
		if !scalar.EqualWithinAbsOrRel(cosqbt, 0, tol, tol) {
			t.Errorf("unexpected cosqbt value for n=%d: got:%f want:0", test.n, cosqbt)
		}

		// Construct a frequency spectrum and compare the computed sequence.
		for i := 0; i < test.n; i++ {
			y[i] = 0.5 * x[0]
			arg := float64(2*i+1) * dt
			for k := 1; k < test.n; k++ {
				y[i] += x[k] * math.Cos(float64(k)*arg)
			}
			y[i] *= 2
		}

		Cosqf(test.n, x, work, ifac)

		var cosqft float64
		for i := 0; i < test.n; i++ {
			cosqft = math.Max(cosqft, math.Abs(x[i]-y[i]))
			x[i] = xh[i]
			y[i] = xh[i]
		}
		cosqft *= cf
		if !scalar.EqualWithinAbsOrRel(cosqft, 0, tol, tol) {
			t.Errorf("unexpected cosqft value for n=%d: got:%f want:0", test.n, cosqft)
		}

		// Check that Cosqb and Cosqf are inverses.
		Cosqb(test.n, x, work, ifac)
		Cosqf(test.n, x, work, ifac)

		var cosqfb float64
		for i := 0; i < test.n; i++ {
			cosqfb = math.Max(cosqfb, math.Abs(cf*x[i]-y[i]))
		}
		if !scalar.EqualWithinAbsOrRel(cosqfb, 0, tol, tol) {
			t.Errorf("unexpected cosqfb value for n=%d: got:%f want:0", test.n, cosqfb)
		}
	}
}

func TestSinq(t *testing.T) {
	t.Parallel()
	const tol = 1e-12
	for _, test := range sincosqTests {
		// Compute the work and factor slices and compare to known values.
		work := make([]float64, 3*test.n)
		ifac := make([]int, 15)
		Sinqi(test.n, work, ifac)
		var failed bool
		if !floats.EqualApprox(work, test.wantiwork, 1e-6) {
			failed = true
			t.Errorf("unexpected work after call to sinqi for n=%d", test.n)
			t.Logf("\n%v\n%v", work, test.wantiwork)
		}
		if !reflect.DeepEqual(ifac, test.wantiifac) {
			failed = true
			t.Errorf("unexpected ifac after call to sinqi for n=%d", test.n)
		}
		if failed {
			continue
		}

		// Construct a sequence with known a frequency spectrum and compare
		// the computed spectrum.
		fn := float64(test.n)
		x := make([]float64, test.n)
		y, _, xh := series(test.n)

		dt := math.Pi / (2 * fn)
		for i := 0; i < test.n; i++ {
			arg := float64(i+1) * dt
			for k := 0; k < test.n; k++ {
				x[i] += y[k] * math.Sin(float64(2*k+1)*arg)
			}
			x[i] *= 4
		}

		Sinqb(test.n, y, work, ifac)

		cf := 0.25 / fn
		var sinqbt float64
		for i := 0; i < test.n; i++ {
			sinqbt = math.Max(sinqbt, math.Abs(x[i]-y[i]))
			x[i] = xh[i]
		}
		sinqbt *= cf
		if !scalar.EqualWithinAbsOrRel(sinqbt, 0, tol, tol) {
			t.Errorf("unexpected sinqbt value for n=%d: got:%f want:0", test.n, sinqbt)
		}

		// Construct a frequency spectrum and compare the computed sequence.
		for i := 0; i < test.n; i++ {
			arg := float64(2*i+1) * dt
			y[i] = 0.5 * math.Pow(-1, float64(i)) * x[test.n-1]
			for k := 0; k < test.n-1; k++ {
				y[i] += x[k] * math.Sin(float64(k+1)*arg)
			}
			y[i] *= 2
		}

		Sinqf(test.n, x, work, ifac)

		var sinqft float64
		for i := 0; i < test.n; i++ {
			sinqft = math.Max(sinqft, math.Abs(x[i]-y[i]))
			x[i] = xh[i]
			y[i] = xh[i]
		}
		sinqft *= cf
		if !scalar.EqualWithinAbsOrRel(sinqft, 0, tol, tol) {
			t.Errorf("unexpected sinqft value for n=%d: got:%f want:0", test.n, sinqft)
		}

		// Check that Sinqb and Sinqf are inverses.
		Sinqb(test.n, x, work, ifac)
		Sinqf(test.n, x, work, ifac)

		var sinqfb float64
		for i := 0; i < test.n; i++ {
			sinqfb = math.Max(sinqfb, math.Abs(cf*x[i]-y[i]))
		}
		if !scalar.EqualWithinAbsOrRel(sinqfb, 0, tol, tol) {
			t.Errorf("unexpected sinqfb value for n=%d: got:%f want:0", test.n, sinqfb)
		}
	}
}

var sincosqTests = []struct {
	n int

	// The following two fields are added as there is no unit testing in
	// FFTPACK for SINTI.
	//
	// wantiwork is obtained from the FFTPACK test.f with modification.
	// The W array is zeroed at each iteration and the first 3n elements
	// of W are printed after the call to RFFTI.
	wantiwork []float64
	// wantiifac is obtained from the FFTPACK sint.f with modification.
	// The IFAC array is zeroed at each iteration of test.f and the 15 elements
	// of IFAC are printed before RFFTI returns.
	wantiifac []int
}{
	{
		n: 120,

		wantiwork: []float64{
			0.9999143, 0.9996573, 0.9992290, 0.9986295, 0.9978589, 0.9969173, 0.9958049, 0.9945219,
			0.9930685, 0.9914449, 0.9896514, 0.9876884, 0.9855561, 0.9832549, 0.9807853, 0.9781476,
			0.9753423, 0.9723699, 0.9692309, 0.9659258, 0.9624552, 0.9588197, 0.9550200, 0.9510565,
			0.9469301, 0.9426415, 0.9381914, 0.9335804, 0.9288096, 0.9238795, 0.9187912, 0.9135454,
			0.9081432, 0.9025853, 0.8968728, 0.8910065, 0.8849877, 0.8788171, 0.8724960, 0.8660254,
			0.8594064, 0.8526402, 0.8457278, 0.8386706, 0.8314696, 0.8241262, 0.8166415, 0.8090170,
			0.8012538, 0.7933533, 0.7853169, 0.7771459, 0.7688418, 0.7604060, 0.7518398, 0.7431448,
			0.7343225, 0.7253744, 0.7163019, 0.7071068, 0.6977904, 0.6883546, 0.6788007, 0.6691306,
			0.6593458, 0.6494480, 0.6394390, 0.6293204, 0.6190940, 0.6087614, 0.5983246, 0.5877852,
			0.5771452, 0.5664062, 0.5555702, 0.5446390, 0.5336145, 0.5224985, 0.5112931, 0.5000000,
			0.4886212, 0.4771588, 0.4656145, 0.4539905, 0.4422887, 0.4305110, 0.4186597, 0.4067366,
			0.3947438, 0.3826834, 0.3705574, 0.3583679, 0.3461170, 0.3338068, 0.3214395, 0.3090170,
			0.2965415, 0.2840153, 0.2714404, 0.2588191, 0.2461533, 0.2334453, 0.2206974, 0.2079117,
			0.1950902, 0.1822355, 0.1693494, 0.1564344, 0.1434926, 0.1305261, 0.1175374, 0.1045284,
			0.9150153e-01, 0.7845908e-01, 0.6540307e-01, 0.5233597e-01, 0.3925979e-01, 0.2617688e-01, 0.1308960e-01, -0.4371139e-07,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.9986295, 0.5233596e-01, 0.9945219, 0.1045285, 0.9876884, 0.1564345, 0.9781476, 0.2079117,
			0.9659258, 0.2588190, 0.9510565, 0.3090170, 0.9335804, 0.3583679, 0.9135454, 0.4067366,
			0.8910065, 0.4539905, 0.8660254, 0.5000000, 0.8386706, 0.5446391, 0.8090170, 0.5877852,
			0.7771459, 0.6293204, 0.7431448, 0.6691306, 0.7071068, 0.7071068, 0.6691306, 0.7431449,
			0.6293204, 0.7771460, 0.5877852, 0.8090170, 0.5446390, 0.8386706, 0.5000000, 0.8660254,
			0.4539905, 0.8910065, 0.4067366, 0.9135455, 0.3583679, 0.9335805, 0.3090170, 0.9510565,
			0.2588191, 0.9659258, 0.2079117, 0.9781476, 0.1564344, 0.9876884, 0.1045284, 0.9945219,
			0.5233597e-01, 0.9986295, 0.000000, 0.000000, 0.9945219, 0.1045285, 0.9781476, 0.2079117,
			0.9510565, 0.3090170, 0.9135454, 0.4067366, 0.8660254, 0.5000000, 0.8090170, 0.5877852,
			0.7431448, 0.6691306, 0.000000, 0.9781476, 0.2079117, 0.9135454, 0.4067366, 0.8090170,
			0.5877852, 0.6691306, 0.7431449, 0.5000000, 0.8660254, 0.3090170, 0.9510565, 0.1045284,
			0.9945219, 0.000000, 0.9510565, 0.3090170, 0.8090170, 0.5877852, 0.5877852, 0.8090170,
			0.3090170, 0.9510565, -0.4371139e-07, 1.000000, -0.3090170, 0.9510565, -0.5877852, 0.8090170,
			0.000000, 0.9135454, 0.4067366, 0.6691306, 0.7431449, 0.000000, 0.6691306, 0.7431449,
			-0.1045285, 0.9945219, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
		},
		wantiifac: []int{120, 4, 2, 4, 3, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 54,

		wantiwork: []float64{
			0.9995769, 0.9983082, 0.9961947, 0.9932383, 0.9894416, 0.9848077, 0.9793406, 0.9730449,
			0.9659258, 0.9579895, 0.9492427, 0.9396926, 0.9293475, 0.9182161, 0.9063078, 0.8936327,
			0.8802014, 0.8660254, 0.8511167, 0.8354878, 0.8191521, 0.8021232, 0.7844157, 0.7660444,
			0.7470251, 0.7273737, 0.7071068, 0.6862416, 0.6647958, 0.6427876, 0.6202354, 0.5971586,
			0.5735765, 0.5495090, 0.5249766, 0.5000000, 0.4746003, 0.4487992, 0.4226182, 0.3960797,
			0.3692062, 0.3420202, 0.3145447, 0.2868032, 0.2588191, 0.2306159, 0.2022175, 0.1736482,
			0.1449319, 0.1160929, 0.8715568e-01, 0.5814485e-01, 0.2908471e-01, -0.4371139e-07, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.9932383, 0.1160929, 0.9730449, 0.2306159,
			0.9396926, 0.3420201, 0.8936327, 0.4487992, 0.8354878, 0.5495090, 0.7660444, 0.6427876,
			0.6862416, 0.7273737, 0.5971586, 0.8021232, 0.5000000, 0.8660254, 0.3960797, 0.9182161,
			0.2868032, 0.9579895, 0.1736482, 0.9848077, 0.5814485e-01, 0.9983082, 0.000000, 0.9730449,
			0.2306159, 0.8936327, 0.4487992, 0.7660444, 0.6427876, 0.5971586, 0.8021232, 0.000000,
			0.8936327, 0.4487992, 0.5971586, 0.8021232, 0.1736482, 0.9848077, -0.2868032, 0.9579895,
			0.000000, 0.7660444, 0.6427876, 0.000000, 0.1736482, 0.9848077, 0.000000, 0.000000,
			0.000000, 0.000000,
		},
		wantiifac: []int{54, 4, 2, 3, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 49,

		wantiwork: []float64{
			0.9994862, 0.9979454, 0.9953791, 0.9917900, 0.9871818, 0.9815592, 0.9749279, 0.9672949,
			0.9586679, 0.9490557, 0.9384684, 0.9269168, 0.9144126, 0.9009688, 0.8865993, 0.8713187,
			0.8551428, 0.8380881, 0.8201723, 0.8014136, 0.7818314, 0.7614459, 0.7402779, 0.7183493,
			0.6956825, 0.6723009, 0.6482283, 0.6234898, 0.5981105, 0.5721166, 0.5455348, 0.5183925,
			0.4907175, 0.4625383, 0.4338836, 0.4047833, 0.3752669, 0.3453650, 0.3151082, 0.2845275,
			0.2536545, 0.2225209, 0.1911586, 0.1595999, 0.1278771, 0.9602292e-01, 0.6407014e-01, 0.3205151e-01,
			-0.4371139e-07, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.9917900, 0.1278772, 0.9672949, 0.2536546, 0.9269168, 0.3752670,
			0.000000, 0.9672949, 0.2536546, 0.8713187, 0.4907176, 0.7183493, 0.6956826, 0.000000,
			0.9269168, 0.3752670, 0.7183493, 0.6956826, 0.4047833, 0.9144127, 0.000000, 0.8713187,
			0.4907176, 0.5183925, 0.8551428, 0.3205151e-01, 0.9994862, 0.000000, 0.8014136, 0.5981106,
			0.2845275, 0.9586679, -0.3453652, 0.9384683, 0.000000, 0.7183493, 0.6956826, 0.3205151e-01,
			0.9994862, -0.6723010, 0.7402779, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000,
		},
		wantiifac: []int{49, 2, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 32,

		wantiwork: []float64{
			0.9987954, 0.9951847, 0.9891765, 0.9807853, 0.9700313, 0.9569404, 0.9415441, 0.9238795,
			0.9039893, 0.8819212, 0.8577286, 0.8314696, 0.8032075, 0.7730104, 0.7409511, 0.7071068,
			0.6715589, 0.6343933, 0.5956993, 0.5555702, 0.5141027, 0.4713967, 0.4275551, 0.3826834,
			0.3368898, 0.2902846, 0.2429801, 0.1950902, 0.1467305, 0.9801713e-01, 0.4906765e-01, -0.4371139e-07,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.9807853, 0.1950903, 0.9238795, 0.3826835, 0.8314696, 0.5555702, 0.7071068, 0.7071068,
			0.5555702, 0.8314697, 0.3826834, 0.9238795, 0.1950902, 0.9807853, 0.000000, 0.000000,
			0.9238795, 0.3826835, 0.000000, 0.000000, 0.7071068, 0.7071068, 0.000000, 0.000000,
			0.3826834, 0.9238795, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
		},
		wantiifac: []int{32, 3, 2, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 25,

		wantiwork: []float64{
			0.9980267, 0.9921147, 0.9822872, 0.9685832, 0.9510565, 0.9297765, 0.9048271, 0.8763067,
			0.8443279, 0.8090170, 0.7705132, 0.7289686, 0.6845471, 0.6374239, 0.5877852, 0.5358267,
			0.4817536, 0.4257792, 0.3681245, 0.3090170, 0.2486898, 0.1873812, 0.1253331, 0.6279038e-01,
			-0.4371139e-07, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.9685832, 0.2486899, 0.8763067, 0.4817537, 0.000000, 0.8763067,
			0.4817537, 0.5358267, 0.8443279, 0.000000, 0.7289686, 0.6845471, 0.6279038e-01, 0.9980267,
			0.000000, 0.5358267, 0.8443279, -0.4257794, 0.9048270, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000,
		},
		wantiifac: []int{25, 2, 5, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 4,

		wantiwork: []float64{
			0.9238795, 0.7071068, 0.3826834, -0.4371139e-07, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000, 0.000000, 0.000000, 0.000000,
		},
		wantiifac: []int{4, 1, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 3,

		wantiwork: []float64{
			0.8660254, 0.5000000, -0.4371139e-07, 0.000000, 0.000000, 0.000000, 0.000000, 0.000000,
			0.000000,
		},
		wantiifac: []int{3, 1, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
	{
		n: 2,

		wantiwork: []float64{
			0.7071068, -0.4371139e-07, 0.000000, 0.000000, 0.000000, 0.000000,
		},
		wantiifac: []int{2, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
	},
}

// series returns three copies of a sinusoidal sequence n samples long.
func series(n int) (x, y, xh []float64) {
	x = make([]float64, n)
	y = make([]float64, n)
	xh = make([]float64, n)
	for i := 0; i < n; i++ {
		x[i] = math.Sin(float64(i+1) * math.Sqrt2)
		y[i] = x[i]
		xh[i] = x[i]
	}
	return x, y, xh
}
