fourier: add DCT, DST and QW-FFT APIs
diff --git a/fourier/fourier_sincos.go b/fourier/fourier_sincos.go
new file mode 100644
index 0000000..f1686cf
--- /dev/null
+++ b/fourier/fourier_sincos.go
@@ -0,0 +1,231 @@
+// 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.
+
+package fourier
+
+// DCT implements Discrete Cosine Transform for real sequences.
+type DCT struct {
+	work []float64
+	ifac [15]int
+}
+
+// NewDCT returns a DCT initialized for work on sequences of length n.
+func NewDCT(n int) *DCT {
+	var t DCT
+	t.Reset(n)
+	return &t
+}
+
+// Len returns the length of the acceptable input.
+func (t *DCT) Len() int { return len(t.work) / 3 }
+
+// Reset reinitializes the DCT for work on sequences of length n.
+func (t *DCT) Reset(n int) {
+	if 3*n <= cap(t.work) {
+		t.work = t.work[:3*n]
+	} else {
+		t.work = make([]float64, 3*n)
+	}
+	costi(n, t.work, t.ifac[:])
+}
+
+// Transform computes the Discrete Fourier Cosine Transform of
+// the input data, src, placing the result in dst and returning it.
+// This transform is unnormalized since a call to Transform followed by
+// another call to Transform will multiply the input sequence by 2*(n-1),
+// where n is the length of the sequence.
+//
+// If the length of src is not t.Len(), Transform will panic.
+// If dst is nil, a new slice is allocated and returned. If dst is not nil and
+// the length of dst does not equal t.Len(), FFT will panic.
+// It is safe to use the same slice for dst and src.
+func (t *DCT) Transform(dst, src []float64) []float64 {
+	if len(src) != t.Len() {
+		panic("fourier: sequence length mismatch")
+	}
+	if dst == nil {
+		dst = make([]float64, t.Len())
+	} else if len(dst) != len(src) {
+		panic("fourier: destination length mismatch")
+	}
+	copy(dst, src)
+	cost(len(dst), dst, t.work, t.ifac[:])
+	return dst
+}
+
+// DST implements Discrete Sine Transform for real sequences.
+type DST struct {
+	work []float64
+	ifac [15]int
+}
+
+// NewDST returns a DST initialized for work on sequences of length n.
+func NewDST(n int) *DST {
+	var t DST
+	t.Reset(n)
+	return &t
+}
+
+// Len returns the length of the acceptable input.
+func (t *DST) Len() int { return 2*len(t.work)/5 - 1 }
+
+// Reset reinitializes the DCT for work on sequences of length n.
+func (t *DST) Reset(n int) {
+	if 5*(n+1)/2 <= cap(t.work) {
+		t.work = t.work[:5*(n+1)/2]
+	} else {
+		t.work = make([]float64, 5*(n+1)/2)
+	}
+	sinti(n, t.work, t.ifac[:])
+}
+
+// Transform computes the Discrete Fourier Sine Transform of the input
+// data, src, placing the result in dst and returning it.
+// This transform is unnormalized since a call to Transform followed by
+// another call to Transform will multiply the input sequence by 2*(n-1),
+// where n is the length of the sequence.
+//
+// If the length of src is not t.Len(), Transform will panic.
+// If dst is nil, a new slice is allocated and returned. If dst is not nil and
+// the length of dst does not equal t.Len(), FFT will panic.
+// It is safe to use the same slice for dst and src.
+func (t *DST) Transform(dst, src []float64) []float64 {
+	if len(src) != t.Len() {
+		panic("fourier: sequence length mismatch")
+	}
+	if dst == nil {
+		dst = make([]float64, t.Len())
+	} else if len(dst) != len(src) {
+		panic("fourier: destination length mismatch")
+	}
+	copy(dst, src)
+	sint(len(dst), dst, t.work, t.ifac[:])
+	return dst
+}
+
+// QuarterWaveFFT implements Fast Fourier Transform for quarter wave data..
+type QuarterWaveFFT struct {
+	work []float64
+	ifac [15]int
+}
+
+// NewQuarterWave returns a QuarterWave initialized for work on sequences of length n.
+func NewQuarterWaveFFT(n int) *QuarterWaveFFT {
+	var t QuarterWaveFFT
+	t.Reset(n)
+	return &t
+}
+
+// Len returns the length of the acceptable input.
+func (t *QuarterWaveFFT) Len() int { return len(t.work) / 3 }
+
+// Reset reinitializes the QuarterWaveFFT for work on sequences of length n.
+func (t *QuarterWaveFFT) Reset(n int) {
+	if 3*n <= cap(t.work) {
+		t.work = t.work[:3*n]
+	} else {
+		t.work = make([]float64, 3*n)
+	}
+	cosqi(n, t.work, t.ifac[:])
+}
+
+// CosFFT computes the Fast Fourier Transform of quarter wave data for
+// the input sequence, seq, placing the cosine series coefficients in dst and
+// returning it.
+// This transform is unnormalized since a call to CosFFT followed by a call
+// to CosIFFT will multiply the input sequence by 4*n, where n is the length
+// of the sequence.
+//
+// If the length of seq is not t.Len(), Transform will panic.
+// If dst is nil, a new slice is allocated and returned. If dst is not nil and
+// the length of dst does not equal t.Len(), FFT will panic.
+// It is safe to use the same slice for dst and seq.
+func (t *QuarterWaveFFT) CosFFT(dst, seq []float64) []float64 {
+	if len(seq) != t.Len() {
+		panic("fourier: sequence length mismatch")
+	}
+	if dst == nil {
+		dst = make([]float64, t.Len())
+	} else if len(dst) != len(seq) {
+		panic("fourier: destination length mismatch")
+	}
+	copy(dst, seq)
+	cosqf(len(dst), dst, t.work, t.ifac[:])
+	return dst
+}
+
+// CosIFFT computes the Inverse Fast Fourier Transform of quarter wave data for
+// the input cosine series coefficients, coeff, placing the sequence data in dst
+// and returning it.
+// This transform is unnormalized since a call to CosIFFT followed by a call
+// to CosFFT will multiply the input sequence by 4*n, where n is the length
+// of the sequence.
+//
+// If the length of seq is not t.Len(), Transform will panic.
+// If dst is nil, a new slice is allocated and returned. If dst is not nil and
+// the length of dst does not equal t.Len(), FFT will panic.
+// It is safe to use the same slice for dst and seq.
+func (t *QuarterWaveFFT) CosIFFT(dst, coeff []float64) []float64 {
+	if len(coeff) != t.Len() {
+		panic("fourier: coefficients length mismatch")
+	}
+	if dst == nil {
+		dst = make([]float64, t.Len())
+	} else if len(dst) != len(coeff) {
+		panic("fourier: destination length mismatch")
+	}
+	copy(dst, coeff)
+	cosqb(len(dst), dst, t.work, t.ifac[:])
+	return dst
+}
+
+// SinFFT computes the Fast Fourier Transform of quarter wave data for
+// the input sequence, seq, placing the sine series coefficients in dst and
+// returning it.
+// This transform is unnormalized since a call to SinFFT followed by a call
+// to SinIFFT will multiply the input sequence by 4*n, where n is the length
+// of the sequence.
+//
+// If the length of seq is not t.Len(), Transform will panic.
+// If dst is nil, a new slice is allocated and returned. If dst is not nil and
+// the length of dst does not equal t.Len(), FFT will panic.
+// It is safe to use the same slice for dst and seq.
+func (t *QuarterWaveFFT) SinFFT(dst, seq []float64) []float64 {
+	if len(seq) != t.Len() {
+		panic("fourier: sequence length mismatch")
+	}
+	if dst == nil {
+		dst = make([]float64, t.Len())
+	} else if len(dst) != len(seq) {
+		panic("fourier: destination length mismatch")
+	}
+	copy(dst, seq)
+	sinqf(len(dst), dst, t.work, t.ifac[:])
+	return dst
+}
+
+// SinIFFT computes the Inverse Fast Fourier Transform of quarter wave data for
+// the input sine series coefficients, coeff, placing the sequence data in dst
+// and returning it.
+// This transform is unnormalized since a call to SinIFFT followed by a call
+// to SinFFT will multiply the input sequence by 4*n, where n is the length
+// of the sequence.
+//
+// If the length of seq is not t.Len(), Transform will panic.
+// If dst is nil, a new slice is allocated and returned. If dst is not nil and
+// the length of dst does not equal t.Len(), FFT will panic.
+// It is safe to use the same slice for dst and seq.
+func (t *QuarterWaveFFT) SinIFFT(dst, coeff []float64) []float64 {
+	if len(coeff) != t.Len() {
+		panic("fourier: coefficients length mismatch")
+	}
+	if dst == nil {
+		dst = make([]float64, t.Len())
+	} else if len(dst) != len(coeff) {
+		panic("fourier: destination length mismatch")
+	}
+	copy(dst, coeff)
+	sinqb(len(dst), dst, t.work, t.ifac[:])
+	return dst
+}