Skip to content

Commit ac9920a

Browse files
committed
Style fixes for FFT code.
1 parent a88c45a commit ac9920a

File tree

2 files changed

+65
-51
lines changed

2 files changed

+65
-51
lines changed

src/algorithms/math/fourier-transform/__test__/fastFourierTransform.test.js

+43-27
Original file line numberDiff line numberDiff line change
@@ -2,50 +2,65 @@ import fastFourierTransform from '../fastFourierTransform';
22
import ComplexNumber from '../../complex-number/ComplexNumber';
33

44
/**
5-
* @param {ComplexNumber[]} [seq1]
6-
* @param {ComplexNumber[]} [seq2]
7-
* @param {Number} [eps]
5+
* @param {ComplexNumber[]} sequence1
6+
* @param {ComplexNumber[]} sequence2
7+
* @param {Number} delta
88
* @return {boolean}
99
*/
10-
function approximatelyEqual(seq1, seq2, eps) {
11-
if (seq1.length !== seq2.length) { return false; }
10+
function sequencesApproximatelyEqual(sequence1, sequence2, delta) {
11+
if (sequence1.length !== sequence2.length) {
12+
return false;
13+
}
14+
15+
for (let numberIndex = 0; numberIndex < sequence1.length; numberIndex += 1) {
16+
if (Math.abs(sequence1[numberIndex].re - sequence2[numberIndex].re) > delta) {
17+
return false;
18+
}
1219

13-
for (let i = 0; i < seq1.length; i += 1) {
14-
if (Math.abs(seq1[i].real - seq2[i].real) > eps) { return false; }
15-
if (Math.abs(seq1[i].complex - seq2[i].complex) > eps) { return false; }
20+
if (Math.abs(sequence1[numberIndex].im - sequence2[numberIndex].im) > delta) {
21+
return false;
22+
}
1623
}
1724

1825
return true;
1926
}
2027

28+
const delta = 1e-6;
29+
2130
describe('fastFourierTransform', () => {
2231
it('should calculate the radix-2 discrete fourier transform after zero padding', () => {
23-
const eps = 1e-6;
24-
const in1 = [new ComplexNumber({ re: 0, im: 0 })];
25-
const expOut1 = [new ComplexNumber({ re: 0, im: 0 })];
26-
const out1 = fastFourierTransform(in1);
27-
const invOut1 = fastFourierTransform(out1, true);
28-
expect(approximatelyEqual(expOut1, out1, eps)).toBe(true);
29-
expect(approximatelyEqual(in1, invOut1, eps)).toBe(true);
32+
const input = [new ComplexNumber({ re: 0, im: 0 })];
33+
const expectedOutput = [new ComplexNumber({ re: 0, im: 0 })];
34+
const output = fastFourierTransform(input);
35+
const invertedOutput = fastFourierTransform(output, true);
3036

31-
const in2 = [
37+
expect(sequencesApproximatelyEqual(expectedOutput, output, delta)).toBe(true);
38+
expect(sequencesApproximatelyEqual(input, invertedOutput, delta)).toBe(true);
39+
});
40+
41+
it('should calculate the radix-2 discrete fourier transform after zero padding', () => {
42+
const input = [
3243
new ComplexNumber({ re: 1, im: 2 }),
3344
new ComplexNumber({ re: 2, im: 3 }),
3445
new ComplexNumber({ re: 8, im: 4 }),
3546
];
3647

37-
const expOut2 = [
48+
const expectedOutput = [
3849
new ComplexNumber({ re: 11, im: 9 }),
3950
new ComplexNumber({ re: -10, im: 0 }),
4051
new ComplexNumber({ re: 7, im: 3 }),
4152
new ComplexNumber({ re: -4, im: -4 }),
4253
];
43-
const out2 = fastFourierTransform(in2);
44-
const invOut2 = fastFourierTransform(out2, true);
45-
expect(approximatelyEqual(expOut2, out2, eps)).toBe(true);
46-
expect(approximatelyEqual(in2, invOut2, eps)).toBe(true);
4754

48-
const in3 = [
55+
const output = fastFourierTransform(input);
56+
const invertedOut = fastFourierTransform(output, true);
57+
58+
expect(sequencesApproximatelyEqual(expectedOutput, output, delta)).toBe(true);
59+
expect(sequencesApproximatelyEqual(input, invertedOut, delta)).toBe(true);
60+
});
61+
62+
it('should calculate the radix-2 discrete fourier transform after zero padding', () => {
63+
const input = [
4964
new ComplexNumber({ re: -83656.9359385182, im: 98724.08038374918 }),
5065
new ComplexNumber({ re: -47537.415125808424, im: 88441.58381765135 }),
5166
new ComplexNumber({ re: -24849.657029355192, im: -72621.79007878687 }),
@@ -58,7 +73,7 @@ describe('fastFourierTransform', () => {
5873
new ComplexNumber({ re: -39327.43830818355, im: 30611.949874562706 }),
5974
];
6075

61-
const expOut3 = [
76+
const expectedOutput = [
6277
new ComplexNumber({ re: -203215.3322151, im: -100242.4827503 }),
6378
new ComplexNumber({ re: 99217.0805705, im: 270646.9331932 }),
6479
new ComplexNumber({ re: -305990.9040412, im: 68224.8435751 }),
@@ -77,9 +92,10 @@ describe('fastFourierTransform', () => {
7792
new ComplexNumber({ re: -179002.5662573, im: 239821.0124341 }),
7893
];
7994

80-
const out3 = fastFourierTransform(in3);
81-
const invOut3 = fastFourierTransform(out3, true);
82-
expect(approximatelyEqual(expOut3, out3, eps)).toBe(true);
83-
expect(approximatelyEqual(in3, invOut3, eps)).toBe(true);
95+
const output = fastFourierTransform(input);
96+
const invertedOutput = fastFourierTransform(output, true);
97+
98+
expect(sequencesApproximatelyEqual(expectedOutput, output, delta)).toBe(true);
99+
expect(sequencesApproximatelyEqual(input, invertedOutput, delta)).toBe(true);
84100
});
85101
});

src/algorithms/math/fourier-transform/fastFourierTransform.js

+22-24
Original file line numberDiff line numberDiff line change
@@ -10,68 +10,66 @@ import bitLength from '../bits/bitLength';
1010
*/
1111
function reverseBits(input, bitsCount) {
1212
let reversedBits = 0;
13+
1314
for (let i = 0; i < bitsCount; i += 1) {
1415
reversedBits *= 2;
15-
if (Math.floor(input / (1 << i)) % 2 === 1) { reversedBits += 1; }
16+
17+
if (Math.floor(input / (1 << i)) % 2 === 1) {
18+
reversedBits += 1;
19+
}
1620
}
21+
1722
return reversedBits;
1823
}
1924

2025
/**
2126
* Returns the radix-2 fast fourier transform of the given array.
2227
* Optionally computes the radix-2 inverse fast fourier transform.
2328
*
24-
* @param {ComplexNumber[]} [inputData]
25-
* @param {Boolean} [inverse]
29+
* @param {ComplexNumber[]} inputData
30+
* @param {boolean} [inverse]
2631
* @return {ComplexNumber[]}
2732
*/
2833
export default function fastFourierTransform(inputData, inverse = false) {
2934
const bitsCount = bitLength(inputData.length - 1);
3035
const N = 1 << bitsCount;
3136

3237
while (inputData.length < N) {
33-
inputData.push(new ComplexNumber({
34-
real: 0,
35-
imaginary: 0,
36-
}));
38+
inputData.push(new ComplexNumber());
3739
}
3840

3941
const output = [];
40-
for (let i = 0; i < N; i += 1) { output[i] = inputData[reverseBits(i, bitsCount)]; }
42+
for (let i = 0; i < N; i += 1) {
43+
output[i] = inputData[reverseBits(i, bitsCount)];
44+
}
4145

4246
for (let blockLength = 2; blockLength <= N; blockLength *= 2) {
43-
let phaseStep;
44-
if (inverse) {
45-
phaseStep = new ComplexNumber({
46-
real: Math.cos(2 * Math.PI / blockLength),
47-
imaginary: -1 * Math.sin(2 * Math.PI / blockLength),
48-
});
49-
} else {
50-
phaseStep = new ComplexNumber({
51-
real: Math.cos(2 * Math.PI / blockLength),
52-
imaginary: Math.sin(2 * Math.PI / blockLength),
53-
});
54-
}
47+
const imaginarySign = inverse ? -1 : 1;
48+
const phaseStep = new ComplexNumber({
49+
re: Math.cos(2 * Math.PI / blockLength),
50+
im: imaginarySign * Math.sin(2 * Math.PI / blockLength),
51+
});
5552

5653
for (let blockStart = 0; blockStart < N; blockStart += blockLength) {
57-
let phase = new ComplexNumber({
58-
real: 1,
59-
imaginary: 0,
60-
});
54+
let phase = new ComplexNumber({ re: 1, im: 0 });
6155

6256
for (let idx = blockStart; idx < blockStart + blockLength / 2; idx += 1) {
6357
const upd1 = output[idx].add(output[idx + blockLength / 2].multiply(phase));
6458
const upd2 = output[idx].subtract(output[idx + blockLength / 2].multiply(phase));
59+
6560
output[idx] = upd1;
6661
output[idx + blockLength / 2] = upd2;
62+
6763
phase = phase.multiply(phaseStep);
6864
}
6965
}
7066
}
67+
7168
if (inverse) {
7269
for (let idx = 0; idx < N; idx += 1) {
7370
output[idx] /= N;
7471
}
7572
}
73+
7674
return output;
7775
}

0 commit comments

Comments
 (0)