@@ -48,35 +48,15 @@ macro_rules! impl_fft_for {
48
48
imags. len( )
49
49
) ;
50
50
51
- let mut planner = <$planner>:: new( reals. len( ) , Direction :: Forward ) ;
51
+ let planner = <$planner>:: new( reals. len( ) , direction ) ;
52
52
assert!(
53
53
planner. num_twiddles( ) . is_power_of_two( )
54
54
&& planner. num_twiddles( ) == reals. len( ) / 2
55
55
) ;
56
56
57
57
let opts = Options :: guess_options( reals. len( ) ) ;
58
58
59
- match direction {
60
- Direction :: Reverse => {
61
- for z_im in imags. iter_mut( ) {
62
- * z_im = -* z_im;
63
- }
64
- }
65
- _ => ( ) ,
66
- }
67
-
68
- $opts_and_plan( reals, imags, & opts, & mut planner) ;
69
-
70
- match direction {
71
- Direction :: Reverse => {
72
- let scaling_factor = ( reals. len( ) as $precision) . recip( ) ;
73
- for ( z_re, z_im) in reals. iter_mut( ) . zip( imags. iter_mut( ) ) {
74
- * z_re *= scaling_factor;
75
- * z_im *= -scaling_factor;
76
- }
77
- }
78
- _ => ( ) ,
79
- }
59
+ $opts_and_plan( reals, imags, & opts, & planner) ;
80
60
}
81
61
} ;
82
62
}
@@ -112,30 +92,39 @@ macro_rules! impl_fft_with_opts_and_plan_for {
112
92
reals: & mut [ $precision] ,
113
93
imags: & mut [ $precision] ,
114
94
opts: & Options ,
115
- planner: & mut $planner,
95
+ planner: & $planner,
116
96
) {
117
97
assert!( reals. len( ) == imags. len( ) && reals. len( ) . is_power_of_two( ) ) ;
118
98
let n: usize = reals. len( ) . ilog2( ) as usize ;
119
99
120
- let twiddles_re = & mut planner. twiddles_re;
121
- let twiddles_im = & mut planner. twiddles_im;
100
+ let mut twiddles_re = planner. twiddles_re. clone ( ) ;
101
+ let mut twiddles_im = planner. twiddles_im. clone ( ) ;
122
102
123
103
// We shouldn't be able to execute FFT if the # of twiddles isn't equal to the distance
124
104
// between pairs
125
105
assert!( twiddles_re. len( ) == reals. len( ) / 2 && twiddles_im. len( ) == imags. len( ) / 2 ) ;
126
106
107
+ match planner. direction {
108
+ Direction :: Reverse => {
109
+ for z_im in imags. iter_mut( ) {
110
+ * z_im = -* z_im;
111
+ }
112
+ }
113
+ _ => ( ) ,
114
+ }
115
+
127
116
for t in ( 0 ..n) . rev( ) {
128
117
let dist = 1 << t;
129
118
let chunk_size = dist << 1 ;
130
119
131
120
if chunk_size > 4 {
132
121
if t < n - 1 {
133
- filter_twiddles( twiddles_re, twiddles_im) ;
122
+ ( twiddles_re , twiddles_im ) = filter_twiddles( & twiddles_re, & twiddles_im) ;
134
123
}
135
124
if chunk_size >= $lanes * 2 {
136
- $simd_butterfly_kernel( reals, imags, twiddles_re, twiddles_im, dist) ;
125
+ $simd_butterfly_kernel( reals, imags, & twiddles_re, & twiddles_im, dist) ;
137
126
} else {
138
- fft_chunk_n( reals, imags, twiddles_re, twiddles_im, dist) ;
127
+ fft_chunk_n( reals, imags, & twiddles_re, & twiddles_im, dist) ;
139
128
}
140
129
} else if chunk_size == 2 {
141
130
fft_chunk_2( reals, imags) ;
@@ -153,6 +142,17 @@ macro_rules! impl_fft_with_opts_and_plan_for {
153
142
cobra_apply( reals, n) ;
154
143
cobra_apply( imags, n) ;
155
144
}
145
+
146
+ match planner. direction {
147
+ Direction :: Reverse => {
148
+ let scaling_factor = ( reals. len( ) as $precision) . recip( ) ;
149
+ for ( z_re, z_im) in reals. iter_mut( ) . zip( imags. iter_mut( ) ) {
150
+ * z_re *= scaling_factor;
151
+ * z_im *= -scaling_factor;
152
+ }
153
+ }
154
+ _ => ( ) ,
155
+ }
156
156
}
157
157
} ;
158
158
}
@@ -179,7 +179,7 @@ mod tests {
179
179
180
180
use utilities:: rustfft:: num_complex:: Complex ;
181
181
use utilities:: rustfft:: FftPlanner ;
182
- use utilities:: { assert_float_closeness, gen_random_signal} ;
182
+ use utilities:: { assert_float_closeness, gen_random_signal, gen_random_signal_f32 } ;
183
183
184
184
use super :: * ;
185
185
@@ -308,4 +308,65 @@ mod tests {
308
308
}
309
309
}
310
310
}
311
+
312
+ #[ test]
313
+ fn fft_64_with_opts_and_plan_vs_fft_64 ( ) {
314
+ let num_points = 4096 ;
315
+
316
+ let mut reals = vec ! [ 0.0 ; num_points] ;
317
+ let mut imags = vec ! [ 0.0 ; num_points] ;
318
+ gen_random_signal ( & mut reals, & mut imags) ;
319
+
320
+ let mut re = reals. clone ( ) ;
321
+ let mut im = imags. clone ( ) ;
322
+
323
+ let mut planner = Planner64 :: new ( num_points, Direction :: Forward ) ;
324
+ let opts = Options :: guess_options ( reals. len ( ) ) ;
325
+ fft_64_with_opts_and_plan ( & mut reals, & mut imags, & opts, & mut planner) ;
326
+
327
+ fft_64 ( & mut re, & mut im, Direction :: Forward ) ;
328
+
329
+ reals
330
+ . iter ( )
331
+ . zip ( imags. iter ( ) )
332
+ . zip ( re. iter ( ) )
333
+ . zip ( im. iter ( ) )
334
+ . for_each ( |( ( ( r, i) , z_re) , z_im) | {
335
+ assert_float_closeness ( * r, * z_re, 1e-6 ) ;
336
+ assert_float_closeness ( * i, * z_im, 1e-6 ) ;
337
+ } ) ;
338
+ }
339
+
340
+ #[ test]
341
+ fn fft_32_with_opts_and_plan_vs_fft_64 ( ) {
342
+ let dirs = [ Direction :: Forward , Direction :: Reverse ] ;
343
+
344
+ for direction in dirs {
345
+ for n in 4 ..14 {
346
+ let num_points = 1 << n;
347
+ let mut reals = vec ! [ 0.0 ; num_points] ;
348
+ let mut imags = vec ! [ 0.0 ; num_points] ;
349
+ gen_random_signal_f32 ( & mut reals, & mut imags) ;
350
+
351
+ let mut re = reals. clone ( ) ;
352
+ let mut im = imags. clone ( ) ;
353
+
354
+ let mut planner = Planner32 :: new ( num_points, direction) ;
355
+ let opts = Options :: guess_options ( reals. len ( ) ) ;
356
+ fft_32_with_opts_and_plan ( & mut reals, & mut imags, & opts, & mut planner) ;
357
+
358
+ fft_32 ( & mut re, & mut im, direction) ;
359
+
360
+ reals
361
+ . iter ( )
362
+ . zip ( imags. iter ( ) )
363
+ . zip ( re. iter ( ) )
364
+ . zip ( im. iter ( ) )
365
+ . for_each ( |( ( ( r, i) , z_re) , z_im) | {
366
+ assert_float_closeness ( * r, * z_re, 1e-6 ) ;
367
+ assert_float_closeness ( * i, * z_im, 1e-6 ) ;
368
+ } ) ;
369
+ }
370
+ }
371
+ }
311
372
}
0 commit comments