annotate fft/fftw/fftw-3.3.4/libbench2/verify-lib.c @ 40:223f770b5341 kissfft-double tip

Try a double-precision kissfft
author Chris Cannam
date Wed, 07 Sep 2016 10:40:32 +0100
parents 26056e866c29
children
rev   line source
Chris@19 1 /*
Chris@19 2 * Copyright (c) 2003, 2007-14 Matteo Frigo
Chris@19 3 * Copyright (c) 2003, 2007-14 Massachusetts Institute of Technology
Chris@19 4 *
Chris@19 5 * This program is free software; you can redistribute it and/or modify
Chris@19 6 * it under the terms of the GNU General Public License as published by
Chris@19 7 * the Free Software Foundation; either version 2 of the License, or
Chris@19 8 * (at your option) any later version.
Chris@19 9 *
Chris@19 10 * This program is distributed in the hope that it will be useful,
Chris@19 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Chris@19 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Chris@19 13 * GNU General Public License for more details.
Chris@19 14 *
Chris@19 15 * You should have received a copy of the GNU General Public License
Chris@19 16 * along with this program; if not, write to the Free Software
Chris@19 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Chris@19 18 *
Chris@19 19 */
Chris@19 20
Chris@19 21
Chris@19 22 #include "verify.h"
Chris@19 23 #include <math.h>
Chris@19 24 #include <stdlib.h>
Chris@19 25 #include <stdio.h>
Chris@19 26
Chris@19 27 /*
Chris@19 28 * Utility functions:
Chris@19 29 */
Chris@19 30 static double dabs(double x) { return (x < 0.0) ? -x : x; }
Chris@19 31 static double dmin(double x, double y) { return (x < y) ? x : y; }
Chris@19 32 static double norm2(double x, double y) { return dmax(dabs(x), dabs(y)); }
Chris@19 33
Chris@19 34 double dmax(double x, double y) { return (x > y) ? x : y; }
Chris@19 35
Chris@19 36 static double aerror(C *a, C *b, int n)
Chris@19 37 {
Chris@19 38 if (n > 0) {
Chris@19 39 /* compute the relative Linf error */
Chris@19 40 double e = 0.0, mag = 0.0;
Chris@19 41 int i;
Chris@19 42
Chris@19 43 for (i = 0; i < n; ++i) {
Chris@19 44 e = dmax(e, norm2(c_re(a[i]) - c_re(b[i]),
Chris@19 45 c_im(a[i]) - c_im(b[i])));
Chris@19 46 mag = dmax(mag,
Chris@19 47 dmin(norm2(c_re(a[i]), c_im(a[i])),
Chris@19 48 norm2(c_re(b[i]), c_im(b[i]))));
Chris@19 49 }
Chris@19 50 e /= mag;
Chris@19 51
Chris@19 52 #ifdef HAVE_ISNAN
Chris@19 53 BENCH_ASSERT(!isnan(e));
Chris@19 54 #endif
Chris@19 55 return e;
Chris@19 56 } else
Chris@19 57 return 0.0;
Chris@19 58 }
Chris@19 59
Chris@19 60 #ifdef HAVE_DRAND48
Chris@19 61 # if defined(HAVE_DECL_DRAND48) && !HAVE_DECL_DRAND48
Chris@19 62 extern double drand48(void);
Chris@19 63 # endif
Chris@19 64 double mydrand(void)
Chris@19 65 {
Chris@19 66 return drand48() - 0.5;
Chris@19 67 }
Chris@19 68 #else
Chris@19 69 double mydrand(void)
Chris@19 70 {
Chris@19 71 double d = rand();
Chris@19 72 return (d / (double) RAND_MAX) - 0.5;
Chris@19 73 }
Chris@19 74 #endif
Chris@19 75
Chris@19 76 void arand(C *a, int n)
Chris@19 77 {
Chris@19 78 int i;
Chris@19 79
Chris@19 80 /* generate random inputs */
Chris@19 81 for (i = 0; i < n; ++i) {
Chris@19 82 c_re(a[i]) = mydrand();
Chris@19 83 c_im(a[i]) = mydrand();
Chris@19 84 }
Chris@19 85 }
Chris@19 86
Chris@19 87 /* make array real */
Chris@19 88 void mkreal(C *A, int n)
Chris@19 89 {
Chris@19 90 int i;
Chris@19 91
Chris@19 92 for (i = 0; i < n; ++i) {
Chris@19 93 c_im(A[i]) = 0.0;
Chris@19 94 }
Chris@19 95 }
Chris@19 96
Chris@19 97 static void assign_conj(C *Ac, C *A, int rank, const bench_iodim *dim, int stride)
Chris@19 98 {
Chris@19 99 if (rank == 0) {
Chris@19 100 c_re(*Ac) = c_re(*A);
Chris@19 101 c_im(*Ac) = -c_im(*A);
Chris@19 102 }
Chris@19 103 else {
Chris@19 104 int i, n0 = dim[rank - 1].n, s = stride;
Chris@19 105 rank -= 1;
Chris@19 106 stride *= n0;
Chris@19 107 assign_conj(Ac, A, rank, dim, stride);
Chris@19 108 for (i = 1; i < n0; ++i)
Chris@19 109 assign_conj(Ac + (n0 - i) * s, A + i * s, rank, dim, stride);
Chris@19 110 }
Chris@19 111 }
Chris@19 112
Chris@19 113 /* make array hermitian */
Chris@19 114 void mkhermitian(C *A, int rank, const bench_iodim *dim, int stride)
Chris@19 115 {
Chris@19 116 if (rank == 0)
Chris@19 117 c_im(*A) = 0.0;
Chris@19 118 else {
Chris@19 119 int i, n0 = dim[rank - 1].n, s = stride;
Chris@19 120 rank -= 1;
Chris@19 121 stride *= n0;
Chris@19 122 mkhermitian(A, rank, dim, stride);
Chris@19 123 for (i = 1; 2*i < n0; ++i)
Chris@19 124 assign_conj(A + (n0 - i) * s, A + i * s, rank, dim, stride);
Chris@19 125 if (2*i == n0)
Chris@19 126 mkhermitian(A + i * s, rank, dim, stride);
Chris@19 127 }
Chris@19 128 }
Chris@19 129
Chris@19 130 void mkhermitian1(C *a, int n)
Chris@19 131 {
Chris@19 132 bench_iodim d;
Chris@19 133
Chris@19 134 d.n = n;
Chris@19 135 d.is = d.os = 1;
Chris@19 136 mkhermitian(a, 1, &d, 1);
Chris@19 137 }
Chris@19 138
Chris@19 139 /* C = A */
Chris@19 140 void acopy(C *c, C *a, int n)
Chris@19 141 {
Chris@19 142 int i;
Chris@19 143
Chris@19 144 for (i = 0; i < n; ++i) {
Chris@19 145 c_re(c[i]) = c_re(a[i]);
Chris@19 146 c_im(c[i]) = c_im(a[i]);
Chris@19 147 }
Chris@19 148 }
Chris@19 149
Chris@19 150 /* C = A + B */
Chris@19 151 void aadd(C *c, C *a, C *b, int n)
Chris@19 152 {
Chris@19 153 int i;
Chris@19 154
Chris@19 155 for (i = 0; i < n; ++i) {
Chris@19 156 c_re(c[i]) = c_re(a[i]) + c_re(b[i]);
Chris@19 157 c_im(c[i]) = c_im(a[i]) + c_im(b[i]);
Chris@19 158 }
Chris@19 159 }
Chris@19 160
Chris@19 161 /* C = A - B */
Chris@19 162 void asub(C *c, C *a, C *b, int n)
Chris@19 163 {
Chris@19 164 int i;
Chris@19 165
Chris@19 166 for (i = 0; i < n; ++i) {
Chris@19 167 c_re(c[i]) = c_re(a[i]) - c_re(b[i]);
Chris@19 168 c_im(c[i]) = c_im(a[i]) - c_im(b[i]);
Chris@19 169 }
Chris@19 170 }
Chris@19 171
Chris@19 172 /* B = rotate left A (complex) */
Chris@19 173 void arol(C *b, C *a, int n, int nb, int na)
Chris@19 174 {
Chris@19 175 int i, ib, ia;
Chris@19 176
Chris@19 177 for (ib = 0; ib < nb; ++ib) {
Chris@19 178 for (i = 0; i < n - 1; ++i)
Chris@19 179 for (ia = 0; ia < na; ++ia) {
Chris@19 180 C *pb = b + (ib * n + i) * na + ia;
Chris@19 181 C *pa = a + (ib * n + i + 1) * na + ia;
Chris@19 182 c_re(*pb) = c_re(*pa);
Chris@19 183 c_im(*pb) = c_im(*pa);
Chris@19 184 }
Chris@19 185
Chris@19 186 for (ia = 0; ia < na; ++ia) {
Chris@19 187 C *pb = b + (ib * n + n - 1) * na + ia;
Chris@19 188 C *pa = a + ib * n * na + ia;
Chris@19 189 c_re(*pb) = c_re(*pa);
Chris@19 190 c_im(*pb) = c_im(*pa);
Chris@19 191 }
Chris@19 192 }
Chris@19 193 }
Chris@19 194
Chris@19 195 void aphase_shift(C *b, C *a, int n, int nb, int na, double sign)
Chris@19 196 {
Chris@19 197 int j, jb, ja;
Chris@19 198 trigreal twopin;
Chris@19 199 twopin = K2PI / n;
Chris@19 200
Chris@19 201 for (jb = 0; jb < nb; ++jb)
Chris@19 202 for (j = 0; j < n; ++j) {
Chris@19 203 trigreal s = sign * SIN(j * twopin);
Chris@19 204 trigreal c = COS(j * twopin);
Chris@19 205
Chris@19 206 for (ja = 0; ja < na; ++ja) {
Chris@19 207 int k = (jb * n + j) * na + ja;
Chris@19 208 c_re(b[k]) = c_re(a[k]) * c - c_im(a[k]) * s;
Chris@19 209 c_im(b[k]) = c_re(a[k]) * s + c_im(a[k]) * c;
Chris@19 210 }
Chris@19 211 }
Chris@19 212 }
Chris@19 213
Chris@19 214 /* A = alpha * A (complex, in place) */
Chris@19 215 void ascale(C *a, C alpha, int n)
Chris@19 216 {
Chris@19 217 int i;
Chris@19 218
Chris@19 219 for (i = 0; i < n; ++i) {
Chris@19 220 R xr = c_re(a[i]), xi = c_im(a[i]);
Chris@19 221 c_re(a[i]) = xr * c_re(alpha) - xi * c_im(alpha);
Chris@19 222 c_im(a[i]) = xr * c_im(alpha) + xi * c_re(alpha);
Chris@19 223 }
Chris@19 224 }
Chris@19 225
Chris@19 226
Chris@19 227 double acmp(C *a, C *b, int n, const char *test, double tol)
Chris@19 228 {
Chris@19 229 double d = aerror(a, b, n);
Chris@19 230 if (d > tol) {
Chris@19 231 ovtpvt_err("Found relative error %e (%s)\n", d, test);
Chris@19 232
Chris@19 233 {
Chris@19 234 int i, N;
Chris@19 235 N = n > 300 && verbose <= 2 ? 300 : n;
Chris@19 236 for (i = 0; i < N; ++i)
Chris@19 237 ovtpvt_err("%8d %16.12f %16.12f %16.12f %16.12f\n", i,
Chris@19 238 (double) c_re(a[i]), (double) c_im(a[i]),
Chris@19 239 (double) c_re(b[i]), (double) c_im(b[i]));
Chris@19 240 }
Chris@19 241
Chris@19 242 bench_exit(EXIT_FAILURE);
Chris@19 243 }
Chris@19 244 return d;
Chris@19 245 }
Chris@19 246
Chris@19 247
Chris@19 248 /*
Chris@19 249 * Implementation of the FFT tester described in
Chris@19 250 *
Chris@19 251 * Funda Ergün. Testing multivariate linear functions: Overcoming the
Chris@19 252 * generator bottleneck. In Proceedings of the Twenty-Seventh Annual
Chris@19 253 * ACM Symposium on the Theory of Computing, pages 407-416, Las Vegas,
Chris@19 254 * Nevada, 29 May--1 June 1995.
Chris@19 255 *
Chris@19 256 * Also: F. Ergun, S. R. Kumar, and D. Sivakumar, "Self-testing without
Chris@19 257 * the generator bottleneck," SIAM J. on Computing 29 (5), 1630-51 (2000).
Chris@19 258 */
Chris@19 259
Chris@19 260 static double impulse0(dofft_closure *k,
Chris@19 261 int n, int vecn,
Chris@19 262 C *inA, C *inB, C *inC,
Chris@19 263 C *outA, C *outB, C *outC,
Chris@19 264 C *tmp, int rounds, double tol)
Chris@19 265 {
Chris@19 266 int N = n * vecn;
Chris@19 267 double e = 0.0;
Chris@19 268 int j;
Chris@19 269
Chris@19 270 k->apply(k, inA, tmp);
Chris@19 271 e = dmax(e, acmp(tmp, outA, N, "impulse 1", tol));
Chris@19 272
Chris@19 273 for (j = 0; j < rounds; ++j) {
Chris@19 274 arand(inB, N);
Chris@19 275 asub(inC, inA, inB, N);
Chris@19 276 k->apply(k, inB, outB);
Chris@19 277 k->apply(k, inC, outC);
Chris@19 278 aadd(tmp, outB, outC, N);
Chris@19 279 e = dmax(e, acmp(tmp, outA, N, "impulse", tol));
Chris@19 280 }
Chris@19 281 return e;
Chris@19 282 }
Chris@19 283
Chris@19 284 double impulse(dofft_closure *k,
Chris@19 285 int n, int vecn,
Chris@19 286 C *inA, C *inB, C *inC,
Chris@19 287 C *outA, C *outB, C *outC,
Chris@19 288 C *tmp, int rounds, double tol)
Chris@19 289 {
Chris@19 290 int i, j;
Chris@19 291 double e = 0.0;
Chris@19 292
Chris@19 293 /* check impulsive input */
Chris@19 294 for (i = 0; i < vecn; ++i) {
Chris@19 295 R x = (sqrt(n)*(i+1)) / (double)(vecn+1);
Chris@19 296 for (j = 0; j < n; ++j) {
Chris@19 297 c_re(inA[j + i * n]) = 0;
Chris@19 298 c_im(inA[j + i * n]) = 0;
Chris@19 299 c_re(outA[j + i * n]) = x;
Chris@19 300 c_im(outA[j + i * n]) = 0;
Chris@19 301 }
Chris@19 302 c_re(inA[i * n]) = x;
Chris@19 303 c_im(inA[i * n]) = 0;
Chris@19 304 }
Chris@19 305
Chris@19 306 e = dmax(e, impulse0(k, n, vecn, inA, inB, inC, outA, outB, outC,
Chris@19 307 tmp, rounds, tol));
Chris@19 308
Chris@19 309 /* check constant input */
Chris@19 310 for (i = 0; i < vecn; ++i) {
Chris@19 311 R x = (i+1) / ((double)(vecn+1) * sqrt(n));
Chris@19 312 for (j = 0; j < n; ++j) {
Chris@19 313 c_re(inA[j + i * n]) = x;
Chris@19 314 c_im(inA[j + i * n]) = 0;
Chris@19 315 c_re(outA[j + i * n]) = 0;
Chris@19 316 c_im(outA[j + i * n]) = 0;
Chris@19 317 }
Chris@19 318 c_re(outA[i * n]) = n * x;
Chris@19 319 c_im(outA[i * n]) = 0;
Chris@19 320 }
Chris@19 321
Chris@19 322 e = dmax(e, impulse0(k, n, vecn, inA, inB, inC, outA, outB, outC,
Chris@19 323 tmp, rounds, tol));
Chris@19 324 return e;
Chris@19 325 }
Chris@19 326
Chris@19 327 double linear(dofft_closure *k, int realp,
Chris@19 328 int n, C *inA, C *inB, C *inC, C *outA,
Chris@19 329 C *outB, C *outC, C *tmp, int rounds, double tol)
Chris@19 330 {
Chris@19 331 int j;
Chris@19 332 double e = 0.0;
Chris@19 333
Chris@19 334 for (j = 0; j < rounds; ++j) {
Chris@19 335 C alpha, beta;
Chris@19 336 c_re(alpha) = mydrand();
Chris@19 337 c_im(alpha) = realp ? 0.0 : mydrand();
Chris@19 338 c_re(beta) = mydrand();
Chris@19 339 c_im(beta) = realp ? 0.0 : mydrand();
Chris@19 340 arand(inA, n);
Chris@19 341 arand(inB, n);
Chris@19 342 k->apply(k, inA, outA);
Chris@19 343 k->apply(k, inB, outB);
Chris@19 344
Chris@19 345 ascale(outA, alpha, n);
Chris@19 346 ascale(outB, beta, n);
Chris@19 347 aadd(tmp, outA, outB, n);
Chris@19 348 ascale(inA, alpha, n);
Chris@19 349 ascale(inB, beta, n);
Chris@19 350 aadd(inC, inA, inB, n);
Chris@19 351 k->apply(k, inC, outC);
Chris@19 352
Chris@19 353 e = dmax(e, acmp(outC, tmp, n, "linear", tol));
Chris@19 354 }
Chris@19 355 return e;
Chris@19 356 }
Chris@19 357
Chris@19 358
Chris@19 359
Chris@19 360 double tf_shift(dofft_closure *k,
Chris@19 361 int realp, const bench_tensor *sz,
Chris@19 362 int n, int vecn, double sign,
Chris@19 363 C *inA, C *inB, C *outA, C *outB, C *tmp,
Chris@19 364 int rounds, double tol, int which_shift)
Chris@19 365 {
Chris@19 366 int nb, na, dim, N = n * vecn;
Chris@19 367 int i, j;
Chris@19 368 double e = 0.0;
Chris@19 369
Chris@19 370 /* test 3: check the time-shift property */
Chris@19 371 /* the paper performs more tests, but this code should be fine too */
Chris@19 372
Chris@19 373 nb = 1;
Chris@19 374 na = n;
Chris@19 375
Chris@19 376 /* check shifts across all SZ dimensions */
Chris@19 377 for (dim = 0; dim < sz->rnk; ++dim) {
Chris@19 378 int ncur = sz->dims[dim].n;
Chris@19 379
Chris@19 380 na /= ncur;
Chris@19 381
Chris@19 382 for (j = 0; j < rounds; ++j) {
Chris@19 383 arand(inA, N);
Chris@19 384
Chris@19 385 if (which_shift == TIME_SHIFT) {
Chris@19 386 for (i = 0; i < vecn; ++i) {
Chris@19 387 if (realp) mkreal(inA + i * n, n);
Chris@19 388 arol(inB + i * n, inA + i * n, ncur, nb, na);
Chris@19 389 }
Chris@19 390 k->apply(k, inA, outA);
Chris@19 391 k->apply(k, inB, outB);
Chris@19 392 for (i = 0; i < vecn; ++i)
Chris@19 393 aphase_shift(tmp + i * n, outB + i * n, ncur,
Chris@19 394 nb, na, sign);
Chris@19 395 e = dmax(e, acmp(tmp, outA, N, "time shift", tol));
Chris@19 396 } else {
Chris@19 397 for (i = 0; i < vecn; ++i) {
Chris@19 398 if (realp)
Chris@19 399 mkhermitian(inA + i * n, sz->rnk, sz->dims, 1);
Chris@19 400 aphase_shift(inB + i * n, inA + i * n, ncur,
Chris@19 401 nb, na, -sign);
Chris@19 402 }
Chris@19 403 k->apply(k, inA, outA);
Chris@19 404 k->apply(k, inB, outB);
Chris@19 405 for (i = 0; i < vecn; ++i)
Chris@19 406 arol(tmp + i * n, outB + i * n, ncur, nb, na);
Chris@19 407 e = dmax(e, acmp(tmp, outA, N, "freq shift", tol));
Chris@19 408 }
Chris@19 409 }
Chris@19 410
Chris@19 411 nb *= ncur;
Chris@19 412 }
Chris@19 413 return e;
Chris@19 414 }
Chris@19 415
Chris@19 416
Chris@19 417 void preserves_input(dofft_closure *k, aconstrain constrain,
Chris@19 418 int n, C *inA, C *inB, C *outB, int rounds)
Chris@19 419 {
Chris@19 420 int j;
Chris@19 421 int recopy_input = k->recopy_input;
Chris@19 422
Chris@19 423 k->recopy_input = 1;
Chris@19 424 for (j = 0; j < rounds; ++j) {
Chris@19 425 arand(inA, n);
Chris@19 426 if (constrain)
Chris@19 427 constrain(inA, n);
Chris@19 428
Chris@19 429 acopy(inB, inA, n);
Chris@19 430 k->apply(k, inB, outB);
Chris@19 431 acmp(inB, inA, n, "preserves_input", 0.0);
Chris@19 432 }
Chris@19 433 k->recopy_input = recopy_input;
Chris@19 434 }
Chris@19 435
Chris@19 436
Chris@19 437 /* Make a copy of the size tensor, with the same dimensions, but with
Chris@19 438 the strides corresponding to a "packed" row-major array with the
Chris@19 439 given stride. */
Chris@19 440 bench_tensor *verify_pack(const bench_tensor *sz, int s)
Chris@19 441 {
Chris@19 442 bench_tensor *x = tensor_copy(sz);
Chris@19 443 if (FINITE_RNK(x->rnk) && x->rnk > 0) {
Chris@19 444 int i;
Chris@19 445 x->dims[x->rnk - 1].is = s;
Chris@19 446 x->dims[x->rnk - 1].os = s;
Chris@19 447 for (i = x->rnk - 1; i > 0; --i) {
Chris@19 448 x->dims[i - 1].is = x->dims[i].is * x->dims[i].n;
Chris@19 449 x->dims[i - 1].os = x->dims[i].os * x->dims[i].n;
Chris@19 450 }
Chris@19 451 }
Chris@19 452 return x;
Chris@19 453 }
Chris@19 454
Chris@19 455 static int all_zero(C *a, int n)
Chris@19 456 {
Chris@19 457 int i;
Chris@19 458 for (i = 0; i < n; ++i)
Chris@19 459 if (c_re(a[i]) != 0.0 || c_im(a[i]) != 0.0)
Chris@19 460 return 0;
Chris@19 461 return 1;
Chris@19 462 }
Chris@19 463
Chris@19 464 static int one_accuracy_test(dofft_closure *k, aconstrain constrain,
Chris@19 465 int sign, int n, C *a, C *b,
Chris@19 466 double t[6])
Chris@19 467 {
Chris@19 468 double err[6];
Chris@19 469
Chris@19 470 if (constrain)
Chris@19 471 constrain(a, n);
Chris@19 472
Chris@19 473 if (all_zero(a, n))
Chris@19 474 return 0;
Chris@19 475
Chris@19 476 k->apply(k, a, b);
Chris@19 477 fftaccuracy(n, a, b, sign, err);
Chris@19 478
Chris@19 479 t[0] += err[0];
Chris@19 480 t[1] += err[1] * err[1];
Chris@19 481 t[2] = dmax(t[2], err[2]);
Chris@19 482 t[3] += err[3];
Chris@19 483 t[4] += err[4] * err[4];
Chris@19 484 t[5] = dmax(t[5], err[5]);
Chris@19 485
Chris@19 486 return 1;
Chris@19 487 }
Chris@19 488
Chris@19 489 void accuracy_test(dofft_closure *k, aconstrain constrain,
Chris@19 490 int sign, int n, C *a, C *b, int rounds, int impulse_rounds,
Chris@19 491 double t[6])
Chris@19 492 {
Chris@19 493 int r, i;
Chris@19 494 int ntests = 0;
Chris@19 495 bench_complex czero = {0, 0};
Chris@19 496
Chris@19 497 for (i = 0; i < 6; ++i) t[i] = 0.0;
Chris@19 498
Chris@19 499 for (r = 0; r < rounds; ++r) {
Chris@19 500 arand(a, n);
Chris@19 501 if (one_accuracy_test(k, constrain, sign, n, a, b, t))
Chris@19 502 ++ntests;
Chris@19 503 }
Chris@19 504
Chris@19 505 /* impulses at beginning of array */
Chris@19 506 for (r = 0; r < impulse_rounds; ++r) {
Chris@19 507 if (r > n - r - 1)
Chris@19 508 continue;
Chris@19 509
Chris@19 510 caset(a, n, czero);
Chris@19 511 c_re(a[r]) = c_im(a[r]) = 1.0;
Chris@19 512
Chris@19 513 if (one_accuracy_test(k, constrain, sign, n, a, b, t))
Chris@19 514 ++ntests;
Chris@19 515 }
Chris@19 516
Chris@19 517 /* impulses at end of array */
Chris@19 518 for (r = 0; r < impulse_rounds; ++r) {
Chris@19 519 if (r <= n - r - 1)
Chris@19 520 continue;
Chris@19 521
Chris@19 522 caset(a, n, czero);
Chris@19 523 c_re(a[n - r - 1]) = c_im(a[n - r - 1]) = 1.0;
Chris@19 524
Chris@19 525 if (one_accuracy_test(k, constrain, sign, n, a, b, t))
Chris@19 526 ++ntests;
Chris@19 527 }
Chris@19 528
Chris@19 529 /* randomly-located impulses */
Chris@19 530 for (r = 0; r < impulse_rounds; ++r) {
Chris@19 531 caset(a, n, czero);
Chris@19 532 i = rand() % n;
Chris@19 533 c_re(a[i]) = c_im(a[i]) = 1.0;
Chris@19 534
Chris@19 535 if (one_accuracy_test(k, constrain, sign, n, a, b, t))
Chris@19 536 ++ntests;
Chris@19 537 }
Chris@19 538
Chris@19 539 t[0] /= ntests;
Chris@19 540 t[1] = sqrt(t[1] / ntests);
Chris@19 541 t[3] /= ntests;
Chris@19 542 t[4] = sqrt(t[4] / ntests);
Chris@19 543
Chris@19 544 fftaccuracy_done();
Chris@19 545 }