📄 fftw_2.html
字号:
<H3><A NAME="SEC10">Static Arrays in C</A></H3><P><A NAME="IDX82"></A><P>Multi-dimensional arrays declared statically (that is, at compile time,not necessarily with the <CODE>static</CODE> keyword) in C are <EM>already</EM>in row-major order. You don't have to do anything special to transformthem. (See Section <A HREF="fftw_2.html#SEC4">Complex Multi-dimensional Transforms Tutorial</A>, for anexample of this sort of code.)<H3><A NAME="SEC11">Dynamic Arrays in C</A></H3><P>Often, especially for large arrays, it is desirable to allocate thearrays dynamically, at runtime. This isn't too hard to do, although itis not as straightforward for multi-dimensional arrays as it is forone-dimensional arrays.<P>Creating the array is simple: using a dynamic-allocation routine like<CODE>malloc</CODE>, allocate an array big enough to store N <CODE>fftw_complex</CODE>values, where N is the product of the sizes of the array dimensions(i.e. the total number of complex values in the array). For example,here is code to allocate a 5x12x27 rank 3 array:<A NAME="IDX83"></A><PRE>fftw_complex *an_array;an_array = (fftw_complex *) malloc(5 * 12 * 27 * sizeof(fftw_complex));</PRE><P>Accessing the array elements, however, is more tricky--you can't simplyuse multiple applications of the <SAMP>`[]'</SAMP> operator like you could forstatic arrays. Instead, you have to explicitly compute the offset intothe array using the formula given earlier for row-major arrays. Forexample, to reference the (i,j,k)-th element of the arrayallocated above, you would use the expression <CODE>an_array[k + 27 * (j+ 12 * i)]</CODE>.<P>This pain can be alleviated somewhat by defining appropriate macros, or,in C++, creating a class and overloading the <SAMP>`()'</SAMP> operator.<H3><A NAME="SEC12">Dynamic Arrays in C--The Wrong Way</A></H3><P>A different method for allocating multi-dimensional arrays in C is oftensuggested that is incompatible with <CODE>fftwnd</CODE>: <EM>using it willcause FFTW to die a painful death</EM>. We discuss the technique here,however, because it is so commonly known and used. This method is tocreate arrays of pointers of arrays of pointers of ...etcetera. Forexample, the analogue in this method to the example above is:<PRE>int i,j;fftw_complex ***a_bad_array; /* another way to make a 5x12x27 array */a_bad_array = (fftw_complex ***) malloc(5 * sizeof(fftw_complex **));for (i = 0; i < 5; ++i) { a_bad_array[i] = (fftw_complex **) malloc(12 * sizeof(fftw_complex *)); for (j = 0; j < 12; ++j) a_bad_array[i][j] = (fftw_complex *) malloc(27 * sizeof(fftw_complex));}</PRE><P>As you can see, this sort of array is inconvenient to allocate (anddeallocate). On the other hand, it has the advantage that the(i,j,k)-th element can be referenced simply by<CODE>a_bad_array[i][j][k]</CODE>.<P>If you like this technique and want to maximize convenience in accessingthe array, but still want to pass the array to FFTW, you can use ahybrid method. Allocate the array as one contiguous block, but alsodeclare an array of arrays of pointers that point to appropriate placesin the block. That sort of trick is beyond the scope of thisdocumentation; for more information on multi-dimensional arrays in C,see the <CODE>comp.lang.c</CODE><A HREF="http://www.eskimo.com/~scs/C-faq/s6.html">FAQ</A>.<H2><A NAME="SEC13">Words of Wisdom</A></H2><P><A NAME="IDX84"></A><A NAME="IDX85"></A><P>FFTW implements a method for saving plans to disk and restoring them.In fact, what FFTW does is more general than just saving and loadingplans. The mechanism is called <EM><CODE>wisdom</CODE></EM>. Here, we describethis feature at a high level. See Section <A HREF="fftw_3.html#SEC16">FFTW Reference</A>, for a less casual(but more complete) discussion of how to use <CODE>wisdom</CODE> in FFTW.<P>Plans created with the <CODE>FFTW_MEASURE</CODE> option produce near-optimalFFT performance, but it can take a long time to compute a plan becauseFFTW must actually measure the runtime of many possible plans and selectthe best one. This is designed for the situations where so manytransforms of the same size must be computed that the start-up time isirrelevant. For short initialization times but slightly slowertransforms, we have provided <CODE>FFTW_ESTIMATE</CODE>. The <CODE>wisdom</CODE>mechanism is a way to get the best of both worlds. There are, however,certain caveats that the user must be aware of in using <CODE>wisdom</CODE>.For this reason, <CODE>wisdom</CODE> is an optional feature which is notenabled by default.<P>At its simplest, <CODE>wisdom</CODE> provides a way of saving plans to disk sothat they can be reused in other program runs. You create a plan withthe flags <CODE>FFTW_MEASURE</CODE> and <CODE>FFTW_USE_WISDOM</CODE>, and then savethe <CODE>wisdom</CODE> using <CODE>fftw_export_wisdom</CODE>:<A NAME="IDX86"></A><PRE> plan = fftw_create_plan(..., ... | FFTW_MEASURE | FFTW_USE_WISDOM); fftw_export_wisdom(...);</PRE><P><A NAME="IDX87"></A><P>The next time you run the program, you can restore the <CODE>wisdom</CODE>with <CODE>fftw_import_wisdom</CODE>, and then recreate the plan using thesame flags as before. This time, however, the same optimal plan will becreated very quickly without measurements. (FFTW still needs some timeto compute trigonometric tables, however.) The basic outline is:<PRE> fftw_import_wisdom(...); plan = fftw_create_plan(..., ... | FFTW_USE_WISDOM);</PRE><P><A NAME="IDX88"></A><P>Wisdom is more than mere rote memorization, however. FFTW's<CODE>wisdom</CODE> encompasses all of the knowledge and measurements thatwere used to create the plan for a given size. Therefore, existing<CODE>wisdom</CODE> is also applied to the creation of other plans ofdifferent sizes.<P>Whenever a plan is created with the <CODE>FFTW_MEASURE</CODE> and<CODE>FFTW_USE_WISDOM</CODE> flags, <CODE>wisdom</CODE> is generated. Thereafter,plans for any transform with a similar factorization will be computedmore quickly, so long as they use the <CODE>FFTW_USE_WISDOM</CODE> flag. Infact, for transforms with the same factors and of equal or lesser size,no measurements at all need to be made and an optimal plan can becreated with negligible delay!<P>For example, suppose that you create a plan forN = 2<sup>16</sup>.Then, for any equal or smaller power of two, FFTW can create aplan (with the same direction and flags) quickly, using theprecomputed <CODE>wisdom</CODE>. Even for larger powers of two, or sizes thatare a power of two times some other prime factors, plans will becomputed more quickly than they would otherwise (although somemeasurements still have to be made).<P>The <CODE>wisdom</CODE> is cumulative, and is stored in a global, private datastructure managed internally by FFTW. The storage space required isminimal, proportional to the logarithm of the sizes the <CODE>wisdom</CODE> wasgenerated from. The <CODE>wisdom</CODE> can be forgotten (and its associatedmemory freed) by a call to <CODE>fftw_forget_wisdom()</CODE>; otherwise, it isremembered until the program terminates. It can also be exported to afile, a string, or any other medium using <CODE>fftw_export_wisdom</CODE> andrestored during a subsequent execution of the program (or a differentprogram) using <CODE>fftw_import_wisdom</CODE> (these functions are describedbelow).<P>Because <CODE>wisdom</CODE> is incorporated into FFTW at a very low level, thesame <CODE>wisdom</CODE> can be used for one-dimensional transforms,multi-dimensional transforms, and even the parallel extensions to FFTW.Just include <CODE>FFTW_USE_WISDOM</CODE> in the flags for whatever plans youcreate (i.e., always plan wisely).<P>Plans created with the <CODE>FFTW_ESTIMATE</CODE> plan can use <CODE>wisdom</CODE>,but cannot generate it; only <CODE>FFTW_MEASURE</CODE> plans actually produce<CODE>wisdom</CODE>. Also, plans can only use <CODE>wisdom</CODE> generated fromplans created with the same direction and flags. For example, a size<CODE>42</CODE> <CODE>FFTW_BACKWARD</CODE> transform will not use <CODE>wisdom</CODE>produced by a size <CODE>42</CODE> <CODE>FFTW_FORWARD</CODE> transform. The onlyexception to this rule is that <CODE>FFTW_ESTIMATE</CODE> plans can use<CODE>wisdom</CODE> from <CODE>FFTW_MEASURE</CODE> plans.<H3><A NAME="SEC14">Caveats in Using Wisdom</A></H3><P><A NAME="IDX89"></A><BLOCKQUOTE><i><P>For in much wisdom is much grief, and he that increaseth knowledgeincreaseth sorrow.</i>[Ecclesiastes 1:18]<A NAME="IDX90"></A></BLOCKQUOTE><P>There are pitfalls to using <CODE>wisdom</CODE>, in that it can negate FFTW'sability to adapt to changing hardware and other conditions. For example,it would be perfectly possible to export <CODE>wisdom</CODE> from a programrunning on one processor and import it into a program running on anotherprocessor. Doing so, however, would mean that the second program woulduse plans optimized for the first processor, instead of the one it isrunning on.<P>It should be safe to reuse <CODE>wisdom</CODE> as long as the hardware andprogram binaries remain unchanged. (Actually, the optimal plan maychange even between runs of the same binary on identical hardware, dueto differences in the virtual memory environment, etcetera. Usersseriously interested in performance should worry about this problem,too.) It is likely that, if the same <CODE>wisdom</CODE> is used for twodifferent program binaries, even running on the same machine, the plansmay be sub-optimal because of differing code alignments. It istherefore wise to recreate <CODE>wisdom</CODE> every time an application isrecompiled. The more the underlying hardware and software changesbetween the creation of <CODE>wisdom</CODE> and its use, the greater grows therisk of sub-optimal plans.<H3><A NAME="SEC15">Importing and Exporting Wisdom</A></H3><P><A NAME="IDX91"></A><PRE>void fftw_export_wisdom_to_file(FILE *output_file);fftw_status fftw_import_wisdom_from_file(FILE *input_file);</PRE><P><A NAME="IDX92"></A><A NAME="IDX93"></A><P><CODE>fftw_export_wisdom_to_file</CODE> writes the <CODE>wisdom</CODE> to<CODE>output_file</CODE>, which must be a file open forwriting. <CODE>fftw_import_wisdom_from_file</CODE> reads the <CODE>wisdom</CODE>from <CODE>input_file</CODE>, which must be a file open for reading, andreturns <CODE>FFTW_SUCCESS</CODE> if successful and <CODE>FFTW_FAILURE</CODE>otherwise. In both cases, the file is left open and must be closed bythe caller. It is perfectly fine if other data lie before or after the<CODE>wisdom</CODE> in the file, as long as the file is positioned at thebeginning of the <CODE>wisdom</CODE> data before import.<PRE>char *fftw_export_wisdom_to_string(void);fftw_status fftw_import_wisdom_from_string(const char *input_string)</PRE><P><A NAME="IDX94"></A><A NAME="IDX95"></A><P><CODE>fftw_export_wisdom_to_string</CODE> allocates a string, exports the<CODE>wisdom</CODE> to it in <CODE>NULL</CODE>-terminated format, and returns apointer to the string. If there is an error in allocating or writingthe data, it returns <CODE>NULL</CODE>. The caller is responsible fordeallocating the string (with <CODE>fftw_free</CODE>) when she is done withit. <CODE>fftw_import_wisdom_from_string</CODE> imports the <CODE>wisdom</CODE> from<CODE>input_string</CODE>, returning <CODE>FFTW_SUCCESS</CODE> if successful and<CODE>FFTW_FAILURE</CODE> otherwise.<P>Exporting <CODE>wisdom</CODE> does not affect the store of <CODE>wisdom</CODE>. Imported<CODE>wisdom</CODE> supplements the current store rather than replacing it(except when there is conflicting <CODE>wisdom</CODE>, in which case the older<CODE>wisdom</CODE> is discarded). The format of the exported <CODE>wisdom</CODE> is"nerd-readable" LISP-like ASCII text; we will not document it hereexcept to note that it is insensitive to white space (interested userscan contact us for more details).<A NAME="IDX96"></A><A NAME="IDX97"></A><P>See Section <A HREF="fftw_3.html#SEC16">FFTW Reference</A>, for more information, and for a description ofhow you can implement <CODE>wisdom</CODE> import/export for other mediabesides files and strings.<P>The following is a brief example in which the <CODE>wisdom</CODE> is read froma file, a plan is created (possibly generating more <CODE>wisdom</CODE>), andthen the <CODE>wisdom</CODE> is exported to a string and printed to<CODE>stdout</CODE>.<PRE>{ fftw_plan plan; char *wisdom_string; FILE *input_file; /* open file to read wisdom from */ input_file = fopen("sample.wisdom", "r"); if (FFTW_FAILURE == fftw_import_wisdom_from_file(input_file)) printf("Error reading wisdom!\n"); fclose(input_file); /* be sure to close the file! */ /* create a plan for N=64, possibly creating and/or using wisdom */ plan = fftw_create_plan(64,FFTW_FORWARD, FFTW_MEASURE | FFTW_USE_WISDOM); /* ... do some computations with the plan ... */ /* always destroy plans when you are done */ fftw_destroy_plan(plan); /* write the wisdom to a string */ wisdom_string = fftw_export_wisdom_to_string(); if (wisdom_string != NULL) { printf("Accumulated wisdom: %s\n",wisdom_string); /* Just for fun, destroy and restore the wisdom */ fftw_forget_wisdom(); /* all gone! */ fftw_import_wisdom_from_string(wisdom_string); /* wisdom is back! */ fftw_free(wisdom_string); /* deallocate it since we're done */ }}</PRE><P><HR><P>Go to the <A HREF="fftw_1.html">first</A>, <A HREF="fftw_1.html">previous</A>, <A HREF="fftw_3.html">next</A>, <A HREF="fftw_10.html">last</A> section, <A HREF="fftw_toc.html">table of contents</A>.</BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -