annotate fft/nayukic/ffttest.c @ 40:223f770b5341 kissfft-double tip

Try a double-precision kissfft
author Chris Cannam
date Wed, 07 Sep 2016 10:40:32 +0100
parents ebc87a62321d
children
rev   line source
Chris@32 1 /*
Chris@32 2 * FFT and convolution test (C)
Chris@32 3 *
Chris@32 4 * Copyright (c) 2014 Project Nayuki
Chris@32 5 * http://www.nayuki.io/page/free-small-fft-in-multiple-languages
Chris@32 6 *
Chris@32 7 * (MIT License)
Chris@32 8 * Permission is hereby granted, free of charge, to any person obtaining a copy of
Chris@32 9 * this software and associated documentation files (the "Software"), to deal in
Chris@32 10 * the Software without restriction, including without limitation the rights to
Chris@32 11 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
Chris@32 12 * the Software, and to permit persons to whom the Software is furnished to do so,
Chris@32 13 * subject to the following conditions:
Chris@32 14 * - The above copyright notice and this permission notice shall be included in
Chris@32 15 * all copies or substantial portions of the Software.
Chris@32 16 * - The Software is provided "as is", without warranty of any kind, express or
Chris@32 17 * implied, including but not limited to the warranties of merchantability,
Chris@32 18 * fitness for a particular purpose and noninfringement. In no event shall the
Chris@32 19 * authors or copyright holders be liable for any claim, damages or other
Chris@32 20 * liability, whether in an action of contract, tort or otherwise, arising from,
Chris@32 21 * out of or in connection with the Software or the use or other dealings in the
Chris@32 22 * Software.
Chris@32 23 */
Chris@32 24
Chris@32 25 #include <math.h>
Chris@32 26 #include <stdio.h>
Chris@32 27 #include <stdlib.h>
Chris@32 28 #include <string.h>
Chris@32 29 #include <time.h>
Chris@32 30 #include "fft.h"
Chris@32 31
Chris@32 32
Chris@32 33 // Private function prototypes
Chris@32 34 static void test_fft(int n);
Chris@32 35 static void test_convolution(int n);
Chris@32 36 static void naive_dft(const double *inreal, const double *inimag, double *outreal, double *outimag, int inverse, int n);
Chris@32 37 static void naive_convolve(const double *xreal, const double *ximag, const double *yreal, const double *yimag, double *outreal, double *outimag, int n);
Chris@32 38 static double log10_rms_err(const double *xreal, const double *ximag, const double *yreal, const double *yimag, int n);
Chris@32 39 static double *random_reals(int n);
Chris@32 40 static void *memdup(const void *src, size_t n);
Chris@32 41
Chris@32 42 static double max_log_error = -INFINITY;
Chris@32 43
Chris@32 44
Chris@32 45 /* Main and test functions */
Chris@32 46
Chris@32 47 int main(int argc, char **argv) {
Chris@32 48 int i;
Chris@32 49 int prev;
Chris@32 50 srand(time(NULL));
Chris@32 51
Chris@32 52 // Test power-of-2 size FFTs
Chris@32 53 for (i = 0; i <= 12; i++)
Chris@32 54 test_fft(1 << i);
Chris@32 55
Chris@32 56 // Test small size FFTs
Chris@32 57 for (i = 0; i < 30; i++)
Chris@32 58 test_fft(i);
Chris@32 59
Chris@32 60 // Test diverse size FFTs
Chris@32 61 prev = 0;
Chris@32 62 for (i = 0; i <= 100; i++) {
Chris@32 63 int n = (int)lround(pow(1500, i / 100.0));
Chris@32 64 if (n > prev) {
Chris@32 65 test_fft(n);
Chris@32 66 prev = n;
Chris@32 67 }
Chris@32 68 }
Chris@32 69
Chris@32 70 // Test power-of-2 size convolutions
Chris@32 71 for (i = 0; i <= 12; i++)
Chris@32 72 test_convolution(1 << i);
Chris@32 73
Chris@32 74 // Test diverse size convolutions
Chris@32 75 prev = 0;
Chris@32 76 for (i = 0; i <= 100; i++) {
Chris@32 77 int n = (int)lround(pow(1500, i / 100.0));
Chris@32 78 if (n > prev) {
Chris@32 79 test_convolution(n);
Chris@32 80 prev = n;
Chris@32 81 }
Chris@32 82 }
Chris@32 83
Chris@32 84 printf("\n");
Chris@32 85 printf("Max log err = %.1f\n", max_log_error);
Chris@32 86 printf("Test %s\n", max_log_error < -10 ? "passed" : "failed");
Chris@32 87 return 0;
Chris@32 88 }
Chris@32 89
Chris@32 90
Chris@32 91 static void test_fft(int n) {
Chris@32 92 double *inputreal, *inputimag;
Chris@32 93 double *refoutreal, *refoutimag;
Chris@32 94 double *actualoutreal, *actualoutimag;
Chris@32 95
Chris@32 96 inputreal = random_reals(n);
Chris@32 97 inputimag = random_reals(n);
Chris@32 98
Chris@32 99 refoutreal = malloc(n * sizeof(double));
Chris@32 100 refoutimag = malloc(n * sizeof(double));
Chris@32 101 naive_dft(inputreal, inputimag, refoutreal, refoutimag, 0, n);
Chris@32 102
Chris@32 103 actualoutreal = memdup(inputreal, n * sizeof(double));
Chris@32 104 actualoutimag = memdup(inputimag, n * sizeof(double));
Chris@32 105 transform(actualoutreal, actualoutimag, n);
Chris@32 106
Chris@32 107 printf("fftsize=%4d logerr=%5.1f\n", n, log10_rms_err(refoutreal, refoutimag, actualoutreal, actualoutimag, n));
Chris@32 108
Chris@32 109 free(inputreal);
Chris@32 110 free(inputimag);
Chris@32 111 free(refoutreal);
Chris@32 112 free(refoutimag);
Chris@32 113 free(actualoutreal);
Chris@32 114 free(actualoutimag);
Chris@32 115 }
Chris@32 116
Chris@32 117
Chris@32 118 static void test_convolution(int n) {
Chris@32 119 double *input0real, *input0imag;
Chris@32 120 double *input1real, *input1imag;
Chris@32 121 double *refoutreal, *refoutimag;
Chris@32 122 double *actualoutreal, *actualoutimag;
Chris@32 123
Chris@32 124 input0real = random_reals(n);
Chris@32 125 input0imag = random_reals(n);
Chris@32 126 input1real = random_reals(n);
Chris@32 127 input1imag = random_reals(n);
Chris@32 128
Chris@32 129 refoutreal = malloc(n * sizeof(double));
Chris@32 130 refoutimag = malloc(n * sizeof(double));
Chris@32 131 naive_convolve(input0real, input0imag, input1real, input1imag, refoutreal, refoutimag, n);
Chris@32 132
Chris@32 133 actualoutreal = malloc(n * sizeof(double));
Chris@32 134 actualoutimag = malloc(n * sizeof(double));
Chris@32 135 convolve_complex(input0real, input0imag, input1real, input1imag, actualoutreal, actualoutimag, n);
Chris@32 136
Chris@32 137 printf("convsize=%4d logerr=%5.1f\n", n, log10_rms_err(refoutreal, refoutimag, actualoutreal, actualoutimag, n));
Chris@32 138
Chris@32 139 free(input0real);
Chris@32 140 free(input0imag);
Chris@32 141 free(input1real);
Chris@32 142 free(input1imag);
Chris@32 143 free(refoutreal);
Chris@32 144 free(refoutimag);
Chris@32 145 free(actualoutreal);
Chris@32 146 free(actualoutimag);
Chris@32 147 }
Chris@32 148
Chris@32 149
Chris@32 150 /* Naive reference computation functions */
Chris@32 151
Chris@32 152 static void naive_dft(const double *inreal, const double *inimag, double *outreal, double *outimag, int inverse, int n) {
Chris@32 153 double coef = (inverse ? 2 : -2) * M_PI;
Chris@32 154 int k;
Chris@32 155 for (k = 0; k < n; k++) { // For each output element
Chris@32 156 double sumreal = 0;
Chris@32 157 double sumimag = 0;
Chris@32 158 int t;
Chris@32 159 for (t = 0; t < n; t++) { // For each input element
Chris@32 160 double angle = coef * ((long long)t * k % n) / n;
Chris@32 161 sumreal += inreal[t]*cos(angle) - inimag[t]*sin(angle);
Chris@32 162 sumimag += inreal[t]*sin(angle) + inimag[t]*cos(angle);
Chris@32 163 }
Chris@32 164 outreal[k] = sumreal;
Chris@32 165 outimag[k] = sumimag;
Chris@32 166 }
Chris@32 167 }
Chris@32 168
Chris@32 169
Chris@32 170 static void naive_convolve(const double *xreal, const double *ximag, const double *yreal, const double *yimag, double *outreal, double *outimag, int n) {
Chris@32 171 int i;
Chris@32 172 for (i = 0; i < n; i++) {
Chris@32 173 double sumreal = 0;
Chris@32 174 double sumimag = 0;
Chris@32 175 int j;
Chris@32 176 for (j = 0; j < n; j++) {
Chris@32 177 int k = (i - j + n) % n;
Chris@32 178 sumreal += xreal[k] * yreal[j] - ximag[k] * yimag[j];
Chris@32 179 sumimag += xreal[k] * yimag[j] + ximag[k] * yreal[j];
Chris@32 180 }
Chris@32 181 outreal[i] = sumreal;
Chris@32 182 outimag[i] = sumimag;
Chris@32 183 }
Chris@32 184 }
Chris@32 185
Chris@32 186
Chris@32 187 /* Utility functions */
Chris@32 188
Chris@32 189 static double log10_rms_err(const double *xreal, const double *ximag, const double *yreal, const double *yimag, int n) {
Chris@32 190 double err = 0;
Chris@32 191 int i;
Chris@32 192 for (i = 0; i < n; i++)
Chris@32 193 err += (xreal[i] - yreal[i]) * (xreal[i] - yreal[i]) + (ximag[i] - yimag[i]) * (ximag[i] - yimag[i]);
Chris@32 194
Chris@32 195 err /= n > 0 ? n : 1;
Chris@32 196 err = sqrt(err); // Now this is a root mean square (RMS) error
Chris@32 197 err = err > 0 ? log10(err) : -99.0;
Chris@32 198 if (err > max_log_error)
Chris@32 199 max_log_error = err;
Chris@32 200 return err;
Chris@32 201 }
Chris@32 202
Chris@32 203
Chris@32 204 static double *random_reals(int n) {
Chris@32 205 double *result = malloc(n * sizeof(double));
Chris@32 206 int i;
Chris@32 207 for (i = 0; i < n; i++)
Chris@32 208 result[i] = (rand() / (RAND_MAX + 1.0)) * 2 - 1;
Chris@32 209 return result;
Chris@32 210 }
Chris@32 211
Chris@32 212
Chris@32 213 static void *memdup(const void *src, size_t n) {
Chris@32 214 void *dest = malloc(n);
Chris@32 215 if (dest != NULL)
Chris@32 216 memcpy(dest, src, n);
Chris@32 217 return dest;
Chris@32 218 }