|
class DiscreteCosineTransform |
|
{ |
|
static_assert((Length & (Length - 1)) == 0, "DiscreteCosineTransform size must be a power of 2"); |
|
static_assert(math::is_qnumber<QNumberType>::value || std::is_floating_point_v<QNumberType>, |
|
"DiscreteCosineTransform can only be instantiated with math::QNumber types or floating point."); |
|
|
|
public: |
|
using VectorReal = typename FastFourierTransform<QNumberType>::VectorReal; |
|
using VectorComplex = typename FastFourierTransform<QNumberType>::VectorComplex; |
|
|
|
explicit DiscreteCosineTransform(FastFourierTransform<QNumberType>& fft); |
|
VectorReal& Forward(VectorReal& input); |
|
VectorReal& Inverse(VectorReal& input); |
|
|
|
private: |
|
FastFourierTransform<QNumberType>& fft; |
|
typename infra::BoundedVector<QNumberType>::template WithMaxSize<Length> output; |
|
typename infra::BoundedVector<QNumberType>::template WithMaxSize<Length> reordered; |
|
typename VectorComplex::template WithMaxSize<Length> complexBuffer; |
|
}; |
|
|
|
// Implementation // |
|
|
|
template<typename QNumberType, std::size_t Length> |
|
DiscreteCosineTransform<QNumberType, Length>::DiscreteCosineTransform(FastFourierTransform<QNumberType>& fft) |
|
: fft(fft) |
|
{ |
|
output.resize(Length); |
|
reordered.resize(Length); |
|
complexBuffer.resize(Length); |
|
} |
|
|
|
template<typename QNumberType, std::size_t Length> |
|
OPTIMIZE_FOR_SPEED |
|
typename DiscreteCosineTransform<QNumberType, Length>::VectorReal& |
|
DiscreteCosineTransform<QNumberType, Length>::Forward(VectorReal& input) |
|
{ |
|
for (std::size_t n = 0; n < Length / 2; ++n) |
|
{ |
|
reordered[n] = input[2 * n]; |
|
reordered[Length - 1 - n] = input[2 * n + 1]; |
|
} |
|
|
|
auto& fftResult = fft.Forward(reordered); |
|
|
|
output[0] = QNumberType(math::ToFloat(fftResult[0].Real()) / math::Sqrt(static_cast<float>(Length))); |
|
|
|
for (std::size_t k = 1; k < Length; ++k) |
|
{ |
Audit finding
AUD-0262f479320d805a1f9f35ebe4afaaeeded48913a94Problem
Length == 1satisfies the DCT power-of-two assertion, but the reorder loop executes zero times.Forward([x])transforms the initialized zero buffer and returns zero instead of the mathematically valid one-point DCT[x].Source:
numerical-toolbox-cpp/numerical/analysis/DiscreteCosineTransform.hpp
Lines 17 to 65 in 2f47932
Acceptance criteria
Length >= 2at compile time.TEST_Fminimum-length round-trip/reference case.