1ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// This small program computes a Fast Fourier Transform.  It tests
2ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Valgrind's handling of FP operations.  It is representative of all
3ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// programs that do a lot of FP operations.
4ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
5ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// Licensing: This program is closely based on the one of the same name from
6ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown// http://www.fourmilab.ch/.  The front page of that site says:
7ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//
8ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   "Except for a few clearly-marked exceptions, all the material on this
9ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   site is in the public domain and may be used in any manner without
10ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown//   permission, restriction, attribution, or compensation."
11ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*
13ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	Two-dimensional FFT benchmark
15ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
16ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	Designed and implemented by John Walker in April of 1989.
17ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
18ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	This  benchmark executes a specified number of passes (default
19ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	20) through a loop in which each  iteration  performs  a  fast
20ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	Fourier transform of a square matrix (default size 256x256) of
21ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	complex numbers (default precision double),  followed  by  the
22ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	inverse  transform.   After  all loop iterations are performed
23ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	the results are checked against known correct values.
24ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
25ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	This benchmark is intended for use on C implementations  which
26ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        define  "int"  as  32 bits or longer and permit allocation and
27ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	direct addressing of arrays larger than one megabyte.
28ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
29ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	If CAPOUT is defined,  the  result  after  all	iterations  is
30ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	written  as  a	CA  Lab  pattern  file.   This is intended for
31ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	debugging in case horribly wrong results  are  obtained  on  a
32ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	given machine.
33ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
34ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	Archival  timings  are	run  with the definitions below set as
35ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	follows: Float = double, Asize = 256, Passes = 20, CAPOUT  not
36ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	defined.
37ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
38ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	Time (seconds)		    System
39ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
40ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            2393.93       Sun 3/260, SunOS 3.4, C, "-f68881 -O".
41ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			  (John Walker).
42ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
43ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            1928          Macintosh IIx, MPW C 3.0, "-mc68020
44ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          -mc68881 -elems881 -m".  (Hugh Hoover).
45ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
46ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            1636.1        Sun 4/110, "cc -O3 -lm".  (Michael McClary).
47ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			  The suspicion is that this is software
48ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			  floating point.
49ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
50ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            1556.7        Macintosh II, A/UX, "cc -O -lm"
51ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			  (Michael McClary).
52ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
53ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    1388.8	  Sun 386i/250, SunOS 4.0.1 C
54ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          "-O /usr/lib/trig.il".  (James Carrington).
55ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
56ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    1331.93	  Sun 3/60, SunOS 4.0.1, C,
57ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          "-O4 -f68881 /usr/lib/libm.il"
58ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			  (Bob Elman).
59ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
60ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown            1204.0        Apollo Domain DN4000, C, "-cpu 3000 -opt 4".
61ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			  (Sam Crupi).
62ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
63ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    1174.66	  Compaq 386/25, SCO Xenix 386 C.
64ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			  (Peter Shieh).
65ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
66ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    1068	  Compaq 386/25, SCO Xenix 386,
67ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			  Metaware High C.  (Robert Wenig).
68ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
69ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    1064.0	  Sun 3/80, SunOS 4.0.3 Beta C
70ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          "-O3 -f68881 /usr/lib/libm.il".  (James Carrington).
71ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
72ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    1061.4	  Compaq 386/25, SCO Xenix, High C 1.4.
73ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			  (James Carrington).
74ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
75ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	    1059.79	  Compaq 386/25, 387/25, High C 1.4,
76ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			  DOS|Extender 2.2, 387 inline code
77ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			  generation.  (Nathan Bender).
78ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
79ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	     777.14	  Compaq 386/25, IIT 3C87-25 (387 Compatible),
80ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			  High C 1.5, DOS|Extender 2.2, 387 inline
81ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			  code generation.  (Nathan Bender).
82ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
83ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	     751	  Compaq DeskPro 386/33, High C 1.5 + DOS|Extender,
84ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			  387 code generation.	(James Carrington).
85ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
86ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	     431.44	  Compaq 386/25, Weitek 3167-25, DOS 3.31,
87ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			  High C 1.4, DOS|Extender, Weitek code generation.
88ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			  (Nathan Bender).
89ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
90ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	     344.9	  Compaq 486/25, Metaware High C 1.6, Phar Lap
91ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			  DOS|Extender, in-line floating point.  (Nathan
92ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			  Bender).
93ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
94ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	     324.2	  Data General Motorola 88000, 16 Mhz, Gnu C.
95ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
96ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             323.1        Sun 4/280, C, "-O4".  (Eric Hill).
97ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
98ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	     254	  Compaq SystemPro 486/33, High C 1.5 + DOS|Extender,
99ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			  387 code generation.	(James Carrington).
100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	     242.8	  Silicon Graphics Personal IRIS, MIPS R2000A,
102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          12.5 Mhz, "-O3" (highest level optimisation).
103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			  (Mike Zentner).
104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
105ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             233.0        Sun SPARCStation 1, C, "-O4", SunOS 4.0.3.
106ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			  (Nathan Bender).
107ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
108ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	     187.30	  DEC PMAX 3100, MIPS 2000 chip.
109ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			  (Robert Wenig).
110ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
111ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             120.46       Sun SparcStation 2, C, "-O4", SunOS 4.1.1.
112ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			  (John Walker).
113ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
114ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown             120.21       DEC 3MAX, MIPS 3000, "-O4".
115ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
116ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      98.0	  Intel i860 experimental environment,
117ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			  OS/2, data caching disabled.	(Kern
118ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			  Sibbald).
119ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
120ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      34.9	  Silicon Graphics Indigo�, MIPS R4400,
121ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          175 Mhz, IRIX 5.2, "-O".
122ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
123ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      32.4	  Pentium 133, Windows NT, Microsoft Visual
124ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			  C++ 4.0.
125ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
126ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      17.25	  Silicon Graphics Indigo�, MIPS R4400,
127ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                          175 Mhz, IRIX 6.5, "-O3".
128ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
129ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      14.10	  Dell Dimension XPS R100, Pentium II 400 MHz,
130ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			  Windows 98, Microsoft Visual C 5.0.
131ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
132ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      10.7	  Hewlett-Packard Kayak XU 450Mhz Pentium II,
133ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown			  Microsoft Visual C++ 6.0, Windows NT 4.0sp3.	(Nathan Bender).
134ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
135ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	       5.09	  Sun Ultra 2, UltraSPARC V9, 300 MHz, gcc -O3.
136ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
137ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	       0.846	  Dell Inspiron 9100, Pentium 4, 3.4 GHz, gcc -O3.
138ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
139ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
140ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
141ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <stdio.h>
142ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <stdlib.h>
143ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <math.h>
144ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <string.h>
145ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
146ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*  The  program  may  be  run	with  Float defined as either float or
147ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    double.  With IEEE arithmetic, the same answers are generated  for
148ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    either floating point mode.  */
149ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
150ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define Float	 double 	   /* Floating point type used in FFT */
151ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
152ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define Asize	 256		   /* Array edge size */
153ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define Passes	 20		   /* Number of FFT/Inverse passes */
154ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
155ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define max(a,b) ((a)>(b)?(a):(b))
156ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define min(a,b) ((a)<=(b)?(a):(b))
157ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
158ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*
159ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
160ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	Multi-dimensional fast Fourier transform
161ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
162ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown        Adapted from Press et al., "Numerical Recipes in C".
163ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
164ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown*/
165ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
166ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define SWAP(a,b) tempr=(a); (a)=(b); (b)=tempr
167ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
168ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void fourn(data, nn, ndim, isign)
169ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  Float data[];
170ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  int nn[], ndim, isign;
171ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
172ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	register int i1, i2, i3;
173ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	int i2rev, i3rev, ip1, ip2, ip3, ifp1, ifp2;
174ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	int ibit, idim, k1, k2, n, nprev, nrem, ntot;
175ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	Float tempi, tempr;
176ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	double theta, wi, wpi, wpr, wr, wtemp;
177ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
178ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	ntot = 1;
179ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	for (idim = 1; idim <= ndim; idim++)
180ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   ntot *= nn[idim];
181ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	nprev = 1;
182ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	for (idim = ndim; idim >= 1; idim--) {
183ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   n = nn[idim];
184ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   nrem = ntot / (n * nprev);
185ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   ip1 = nprev << 1;
186ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   ip2 = ip1 * n;
187ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   ip3 = ip2 * nrem;
188ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   i2rev = 1;
189ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   for (i2 = 1; i2 <= ip2; i2 += ip1) {
190ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      if (i2 < i2rev) {
191ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		 for (i1 = i2; i1 <= i2 + ip1 - 2; i1 += 2) {
192ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		    for (i3 = i1; i3 <= ip3; i3 += ip2) {
193ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		       i3rev = i2rev + i3 - i2;
194ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		       SWAP(data[i3], data[i3rev]);
195ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		       SWAP(data[i3 + 1], data[i3rev + 1]);
196ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		    }
197ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		 }
198ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      }
199ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      ibit = ip2 >> 1;
200ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      while (ibit >= ip1 && i2rev > ibit) {
201ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		 i2rev -= ibit;
202ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		 ibit >>= 1;
203ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      }
204ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      i2rev += ibit;
205ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   }
206ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   ifp1 = ip1;
207ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   while (ifp1 < ip2) {
208ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      ifp2 = ifp1 << 1;
209ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      theta = isign * 6.28318530717959 / (ifp2 / ip1);
210ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      wtemp = sin(0.5 * theta);
211ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      wpr = -2.0 * wtemp * wtemp;
212ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      wpi = sin(theta);
213ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      wr = 1.0;
214ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      wi = 0.0;
215ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      for (i3 = 1; i3 <= ifp1; i3 += ip1) {
216ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		 for (i1 = i3; i1 <= i3 + ip1 - 2; i1 += 2) {
217ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		    for (i2 = i1; i2 <= ip3; i2 += ifp2) {
218ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		       k1 = i2;
219ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		       k2 = k1 + ifp1;
220ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		       tempr = wr * data[k2] - wi * data[k2 + 1];
221ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		       tempi = wr * data[k2 + 1] + wi * data[k2];
222ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		       data[k2] = data[k1] - tempr;
223ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		       data[k2 + 1] = data[k1 + 1] - tempi;
224ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		       data[k1] += tempr;
225ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		       data[k1 + 1] += tempi;
226ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		    }
227ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		 }
228ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		 wr = (wtemp = wr) * wpr - wi * wpi + wr;
229ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		 wi = wi * wpr + wtemp * wpi + wi;
230ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      }
231ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      ifp1 = ifp2;
232ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   }
233ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   nprev *= n;
234ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	}
235ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
236ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#undef SWAP
237ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
238ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownint main()
239ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
240ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	int i, j, k, l, m, npasses = Passes, faedge;
241ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	Float *fdata /* , *fd */ ;
242ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	static int nsize[] = {0, 0, 0};
243ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	long fanum, fasize;
244ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	double mapbase, mapscale, /* x, */ rmin, rmax, imin, imax;
245ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
246ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	faedge = Asize; 	   /* FFT array edge size */
247ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	fanum = faedge * faedge;   /* Elements in FFT array */
248ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	fasize = ((fanum + 1) * 2 * sizeof(Float)); /* FFT array size */
249ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	nsize[1] = nsize[2] = faedge;
250ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
251ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	fdata = (Float *) malloc(fasize);
252ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	if (fdata == NULL) {
253ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           fprintf(stdout, "Can't allocate data array.\n");
254ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   exit(1);
255ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	}
256ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
257ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	/*  Generate data array to process.  */
258ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
259ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define Re(x,y) fdata[1 + (faedge * (x) + (y)) * 2]
260ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define Im(x,y) fdata[2 + (faedge * (x) + (y)) * 2]
261ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
262ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	memset(fdata, 0, fasize);
263ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	for (i = 0; i < faedge; i++) {
264ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   for (j = 0; j < faedge; j++) {
265ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      if (((i & 15) == 8) || ((j & 15) == 8))
266ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		 Re(i, j) = 128.0;
267ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   }
268ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	}
269ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
270ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	for (i = 0; i < npasses; i++) {
271ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*printf("Pass %d\n", i);*/
272ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   /* Transform image to frequency domain. */
273ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   fourn(fdata, nsize, 2, 1);
274ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
275ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   /*  Back-transform to image. */
276ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   fourn(fdata, nsize, 2, -1);
277ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	}
278ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
279ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	{
280ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   double r, ij, ar, ai;
281ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   rmin = 1e10; rmax = -1e10;
282ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   imin = 1e10; imax = -1e10;
283ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   ar = 0;
284ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   ai = 0;
285ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
286ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   for (i = 1; i <= fanum; i += 2) {
287ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      r = fdata[i];
288ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      ij = fdata[i + 1];
289ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      ar += r;
290ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      ai += ij;
291ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      rmin = min(r, rmin);
292ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      rmax = max(r, rmax);
293ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      imin = min(ij, imin);
294ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      imax = max(ij, imax);
295ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   }
296ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#ifdef DEBUG
297ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           printf("Real min %.4g, max %.4g.  Imaginary min %.4g, max %.4g.\n",
298ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      rmin, rmax, imin, imax);
299ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           printf("Average real %.4g, imaginary %.4g.\n",
300ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      ar / fanum, ai / fanum);
301ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
302ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   mapbase = rmin;
303ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   mapscale = 255 / (rmax - rmin);
304ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	}
305ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
306ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	/* See if we got the right answers. */
307ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
308ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	m = 0;
309ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	for (i = 0; i < faedge; i++) {
310ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   for (j = 0; j < faedge; j++) {
311ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      k = (Re(i, j) - mapbase) * mapscale;
312ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      l = (((i & 15) == 8) || ((j & 15) == 8)) ? 255 : 0;
313ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      if (k != l) {
314ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		 m++;
315ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		 fprintf(stdout,
316ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    "Wrong answer at (%d,%d)!  Expected %d, got %d.\n",
317ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		    i, j, l, k);
318ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      }
319ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   }
320ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	}
321ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	if (m == 0) {
322ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           fprintf(stdout, "%d passes.  No errors in results.\n", npasses);
323ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	} else {
324ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           fprintf(stdout, "%d passes.  %d errors in results.\n",
325ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      npasses, m);
326ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	}
327ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
328ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#ifdef CAPOUT
329ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
330ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	/* Output the result of the transform as a CA Lab pattern
331ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   file for debugging. */
332ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
333ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	{
334ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define SCRX  322
335ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define SCRY  200
336ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define SCRN  (SCRX * SCRY)
337ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   unsigned char patarr[SCRY][SCRX];
338ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   FILE *fp;
339ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
340ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/*  Map user external state numbers to internal state index  */
341ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
342ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define UtoI(x)     (((((x) >> 1) & 0x7F) | ((x) << 7)) & 0xFF)
343ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
344ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   /* Copy data from FFT buffer to map. */
345ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
346ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   memset(patarr, 0, sizeof patarr);
347ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   l = (SCRX - faedge) / 2;
348ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   m = (faedge > SCRY) ? 0 : ((SCRY - faedge) / 2);
349ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   for (i = 1; i < faedge; i++) {
350ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      for (j = 0; j < min(SCRY, faedge); j++) {
351ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		 k = (Re(i, j) - mapbase) * mapscale;
352ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown		 patarr[j + m][i + l] = UtoI(k);
353ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      }
354ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   }
355ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
356ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   /* Dump pattern map to file. */
357ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
358ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           fp = fopen("fft.cap", "w");
359ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   if (fp == NULL) {
360ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown              fprintf(stdout, "Cannot open output file.\n");
361ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	      exit(0);
362ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   }
363ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown           putc(':', fp);
364ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   putc(1, fp);
365ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   fwrite(patarr, SCRN, 1, fp);
366ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   putc(6, fp);
367ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	   fclose(fp);
368ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	}
369ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
370ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
371ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown	return 0;
372ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
373