├── .travis.yml
├── spec
├── support
│ └── jasmine.json
├── basic-spec.js
├── reversibility-in-place-spec.js
├── TestUtils.js
├── readme-example-spec.js
├── correctness-complex-spec.js
├── correctness-real-spec.js
└── correctness-huge-spec.js
├── appveyor.yml
├── LICENSE
├── package.json
├── .gitignore
├── .circleci
└── config.yml
├── init.js
├── transform.js
├── ooura.js
├── README.md
└── child.js
/.travis.yml:
--------------------------------------------------------------------------------
1 | os: osx
2 | language: node_js
3 | node_js:
4 | - "7"
5 | cache:
6 | directories:
7 | - "node_modules"
8 |
--------------------------------------------------------------------------------
/spec/support/jasmine.json:
--------------------------------------------------------------------------------
1 | {
2 | "spec_dir": "spec",
3 | "spec_files": [
4 | "**/*[sS]pec.js"
5 | ],
6 | "helpers": [
7 | "helpers/**/*.js"
8 | ],
9 | "stopSpecOnExpectationFailure": false,
10 | "random": false
11 | }
12 |
--------------------------------------------------------------------------------
/appveyor.yml:
--------------------------------------------------------------------------------
1 | # Test against the latest version of this Node.js version
2 | environment:
3 | nodejs_version: "6"
4 |
5 | # Install scripts. (runs after repo cloning)
6 | install:
7 | # Get the latest stable version of Node.js or io.js
8 | - ps: Install-Product node $env:nodejs_version
9 | # install modules
10 | - npm install
11 |
12 | # Post-install test scripts.
13 | test_script:
14 | # Output useful info for debugging.
15 | - node --version
16 | - npm --version
17 | # run tests
18 | - npm test
19 |
20 | # Don't actually build.
21 | build: off
22 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2017 Nick Clark
2 |
3 | Permission to use, copy, modify, and distribute this software for any
4 | purpose with or without fee is hereby granted, provided that the above
5 | copyright notice and this permission notice appear in all copies.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
10 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
13 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ooura",
3 | "version": "2.1.6",
4 | "description": "Ultra-fast real/complex FFT with simple interface",
5 | "repository": "https://github.com/audioplastic/ooura",
6 | "main": "ooura.js",
7 | "scripts": {
8 | "test": "xo && jasmine",
9 | "cover": "istanbul cover jasmine",
10 | "coveralls": "istanbul cover jasmine && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage"
11 | },
12 | "xo": {
13 | "rules": {
14 | "one-var": 0,
15 | "no-mixed-operators": 0
16 | },
17 | "ignores": [
18 | "spec/**/*.js"
19 | ]
20 | },
21 | "keywords": [
22 | "fft",
23 | "ooura",
24 | "audio",
25 | "ifft",
26 | "stft",
27 | "dsp",
28 | "overlap-add",
29 | "ola",
30 | "real",
31 | "complex"
32 | ],
33 | "author": "Nick Clark",
34 | "license": "ISC",
35 | "devDependencies": {
36 | "coveralls": "^2.13.1",
37 | "istanbul": "^0.4.5",
38 | "jasmine": "^2.8.0",
39 | "xo": "^0.18.2"
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Runtime data
9 | pids
10 | *.pid
11 | *.seed
12 | *.pid.lock
13 |
14 | # Directory for instrumented libs generated by jscoverage/JSCover
15 | lib-cov
16 |
17 | # Coverage directory used by tools like istanbul
18 | coverage
19 |
20 | # nyc test coverage
21 | .nyc_output
22 |
23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
24 | .grunt
25 |
26 | # Bower dependency directory (https://bower.io/)
27 | bower_components
28 |
29 | # node-waf configuration
30 | .lock-wscript
31 |
32 | # Compiled binary addons (http://nodejs.org/api/addons.html)
33 | build/Release
34 |
35 | # Dependency directories
36 | node_modules/
37 | jspm_packages/
38 |
39 | # Typescript v1 declaration files
40 | typings/
41 |
42 | # Optional npm cache directory
43 | .npm
44 |
45 | # Optional eslint cache
46 | .eslintcache
47 |
48 | # Optional REPL history
49 | .node_repl_history
50 |
51 | # Output of 'npm pack'
52 | *.tgz
53 |
54 | # Yarn Integrity file
55 | .yarn-integrity
56 |
57 | # dotenv environment variables file
58 | .env
59 |
60 | dist
61 | .DS_Store
62 | coverage
63 |
--------------------------------------------------------------------------------
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | # Javascript Node CircleCI 2.0 configuration file
2 | #
3 | # Check https://circleci.com/docs/2.0/language-javascript/ for more details
4 | #
5 | version: 2
6 | jobs:
7 | build:
8 | docker:
9 | # specify the version you desire here
10 | - image: circleci/node:7.10
11 |
12 | # Specify service dependencies here if necessary
13 | # CircleCI maintains a library of pre-built images
14 | # documented at https://circleci.com/docs/2.0/circleci-images/
15 | # - image: circleci/mongo:3.4.4
16 |
17 | working_directory: ~/repo
18 |
19 | steps:
20 | - checkout
21 |
22 | # Download and cache dependencies
23 | - restore_cache:
24 | keys:
25 | - v1-dependencies-{{ checksum "package.json" }}
26 | # fallback to using the latest cache if no exact match is found
27 | - v1-dependencies-
28 |
29 | - run: npm install
30 |
31 | - save_cache:
32 | paths:
33 | - node_modules
34 | key: v1-dependencies-{{ checksum "package.json" }}
35 |
36 | # run tests! (with a naff command handling CircleCI crusty node versions)
37 | - run: npm run coveralls
38 |
--------------------------------------------------------------------------------
/init.js:
--------------------------------------------------------------------------------
1 | const child = require('./child.js');
2 |
3 | exports.makewt = function (nw, ipBuffer, wBuffer) {
4 | let nwh;
5 | let delta;
6 | let x;
7 | let y;
8 |
9 | const ip = new Int16Array(ipBuffer);
10 | const w = new Float64Array(wBuffer);
11 |
12 | ip[0] = nw;
13 | ip[1] = 1;
14 | if (nw > 2) {
15 | nwh = nw >> 1;
16 | delta = Math.atan(1.0) / nwh;
17 | w[0] = 1;
18 | w[1] = 0;
19 | w[nwh] = Math.cos(delta * nwh);
20 | w[nwh + 1] = w[nwh];
21 |
22 | if (nwh > 2) {
23 | for (let j = 2; j < nwh; j += 2) {
24 | x = Math.cos(delta * j);
25 | y = Math.sin(delta * j);
26 | w[j] = x;
27 | w[j + 1] = y;
28 | w[nw - j] = y;
29 | w[nw - j + 1] = x;
30 | }
31 | child.bitrv2(nw, ip.buffer, 2, w.buffer);
32 | }
33 | }
34 | };
35 |
36 | exports.makect = function (nc, ipBuffer, cBuffer, cOffset) {
37 | let j;
38 | let nch;
39 | let delta;
40 |
41 | const ip = new Int16Array(ipBuffer);
42 | const c = new Float64Array(cBuffer).subarray(cOffset);
43 |
44 | ip[1] = nc;
45 | if (nc > 1) {
46 | nch = nc >> 1;
47 | delta = Math.atan(1.0) / nch;
48 | c[0] = Math.cos(delta * nch);
49 | c[nch] = 0.5 * c[0];
50 | for (j = 1; j < nch; j++) {
51 | c[j] = 0.5 * Math.cos(delta * j);
52 | c[nc - j] = 0.5 * Math.sin(delta * j);
53 | }
54 | }
55 | };
56 |
--------------------------------------------------------------------------------
/spec/basic-spec.js:
--------------------------------------------------------------------------------
1 | const Ooura = require('../ooura.js');
2 |
3 | describe('During object setup', () => {
4 | it('should create a valid object with correct real-size and complex-size', () => {
5 | const testSize = 32;
6 | const oo = new Ooura(testSize);
7 | expect(oo.size).toBe(testSize);
8 | expect(oo.getVectorSize()).toBe(1 + testSize / 2);
9 | });
10 |
11 | it('should have a functional complex size static member helper', () => {
12 | expect(Ooura.vectorSize(32)).toBe(17);
13 | expect(Ooura.vectorSize(128)).toBe(65);
14 | });
15 |
16 | it('should have a functional real size static member helper', () => {
17 | expect(Ooura.scalarSize(17)).toBe(32);
18 | expect(Ooura.scalarSize(65)).toBe(128);
19 | });
20 |
21 | it('should have a functional pow2 member helper', () => {
22 | expect(Ooura.isPowerOf2(64)).toBeTruthy();
23 | expect(Ooura.isPowerOf2(8)).toBeTruthy();
24 | expect(Ooura.isPowerOf2(77)).toBeFalsy();
25 | expect(Ooura.isPowerOf2(123)).toBeFalsy();
26 | expect(Ooura.isPowerOf2('Marmot')).toBeFalsy();
27 | });
28 |
29 | it('should return correct array types from factory helpers', () => {
30 | const nfft = 512;
31 | oo = new Ooura(nfft);
32 |
33 | expect(oo.scalarArrayFactory()).toEqual(new Float64Array(nfft));
34 | expect(oo.vectorArrayFactory()).toEqual(new Float64Array(1 + nfft / 2));
35 | });
36 | });
37 |
--------------------------------------------------------------------------------
/transform.js:
--------------------------------------------------------------------------------
1 | const DIRECTION = {
2 | FORWARDS: +1,
3 | BACKWARDS: -1
4 | };
5 | exports.DIRECTION = DIRECTION;
6 |
7 | const child = require('./child.js');
8 |
9 | exports.rdft = function (n, dir, aBuffer, ipBuffer, wBuffer) {
10 | const ip = new Int16Array(ipBuffer);
11 | const a = new Float64Array(aBuffer);
12 | const nw = ip[0];
13 | const nc = ip[1];
14 |
15 | if (dir === DIRECTION.FORWARDS) {
16 | if (n > 4) {
17 | child.bitrv2(n, ipBuffer, 2, aBuffer);
18 | child.cftfsub(n, aBuffer, wBuffer);
19 | child.rftfsub(n, aBuffer, nc, wBuffer, nw);
20 | } else if (n === 4) {
21 | child.cftfsub(n, aBuffer, wBuffer);
22 | }
23 | const xi = a[0] - a[1];
24 | a[0] += a[1];
25 | a[1] = xi;
26 | } else {
27 | a[1] = 0.5 * (a[0] - a[1]);
28 | a[0] -= a[1];
29 | if (n > 4) {
30 | child.rftbsub(n, aBuffer, nc, wBuffer, nw);
31 | child.bitrv2(n, ipBuffer, 2, aBuffer);
32 | child.cftbsub(n, aBuffer, wBuffer);
33 | } else if (n === 4) {
34 | child.cftfsub(n, aBuffer, wBuffer);
35 | }
36 | }
37 | };
38 |
39 | exports.cdft = function (n, dir, aBuffer, ipBuffer, wBuffer) {
40 | if (n > 4) {
41 | if (dir === DIRECTION.FORWARDS) {
42 | child.bitrv2(n, ipBuffer, 2, aBuffer);
43 | child.cftfsub(n, aBuffer, wBuffer);
44 | } else {
45 | child.bitrv2conj(n, ipBuffer, 2, aBuffer);
46 | child.cftbsub(n, aBuffer, wBuffer);
47 | }
48 | } else if (n === 4) {
49 | child.cftfsub(n, aBuffer, wBuffer);
50 | }
51 | };
52 |
--------------------------------------------------------------------------------
/spec/reversibility-in-place-spec.js:
--------------------------------------------------------------------------------
1 | const Ooura = require('../ooura.js');
2 |
3 | describe('When using the in place functions', () => {
4 | it('should have a different real buffer in the forward direction, but return the original in reverse', () => {
5 | const nfft = 32;
6 | const oo = new Ooura(nfft);
7 | const data = Float64Array.from(Array(nfft), (e, i) => i + 1);
8 | const ref = Float64Array.from(Array(nfft), (e, i) => i + 1);
9 | oo.fftInPlace(data.buffer);
10 | expect(data).not.toEqual(ref);
11 | oo.ifftInPlace(data.buffer);
12 |
13 | // Little dirty - just round it or it fails with tiny numerical errors,
14 | // but it proves the general test case under consideration
15 | expect(data.map(x => Math.round(x * 2 / nfft))).toEqual(ref);
16 | });
17 |
18 | it('should have a different complex buffer in the forward direction, but return the original in reverse', () => {
19 | const nfft = 32;
20 | const oo = new Ooura(nfft, {type: 'complex', radix: 4});
21 | const data = Float64Array.from(Array(nfft), (e, i) => i + 1);
22 | const ref = Float64Array.from(Array(nfft), (e, i) => i + 1);
23 | oo.fftInPlace(data.buffer);
24 | expect(data).not.toEqual(ref);
25 | oo.ifftInPlace(data.buffer);
26 |
27 | // Little dirty - just round it or it fails with tiny numerical errors,
28 | // but it proves the general test case under consideration
29 | expect(data.map(x => Math.round(x * 2 / nfft))).toEqual(ref);
30 | });
31 | });
32 |
--------------------------------------------------------------------------------
/spec/TestUtils.js:
--------------------------------------------------------------------------------
1 | const assert = require('assert');
2 | const Ooura = require('../ooura.js');
3 |
4 | const TOLERANCE = 1e-8;
5 |
6 | exports.CheckBuffers = function (a, b) {
7 | assert.equal(a.length, b.length);
8 | let diffs = 0;
9 | for (let nn = 0; nn < a.length; nn++) {
10 | if (Math.abs(a[nn] - b[nn]) > TOLERANCE) {
11 | diffs++;
12 | }
13 | }
14 | return diffs;
15 | };
16 |
17 | exports.TestCorrectnessReal = function (reRef, imRef) {
18 | assert.equal(reRef.length, imRef.length);
19 | const size = Ooura.scalarSize(reRef.length);
20 |
21 | const input = Float64Array.from(Array(size), (e, i) => i + 1); // Fancy-pants way of making 1,2,3, . .
22 |
23 | const oo = new Ooura(size);
24 | const re = oo.vectorArrayFactory();
25 | const im = oo.vectorArrayFactory();
26 | const result = new Object();
27 |
28 | oo.fft(input.buffer, re.buffer, im.buffer);
29 |
30 | result.reDiffs = exports.CheckBuffers(re, reRef);
31 | result.imDiffs = exports.CheckBuffers(im, imRef);
32 |
33 | const backwards = oo.scalarArrayFactory();
34 | oo.ifft(backwards.buffer, re.buffer, im.buffer);
35 | result.reverseDiffs = exports.CheckBuffers(backwards, input);
36 |
37 | return result;
38 | };
39 |
40 | exports.TestCorrectnessComplex = function (reRef, imRef) {
41 | assert.equal(reRef.length, imRef.length);
42 | const size = reRef.length + imRef.length;
43 |
44 | const reIp = Float64Array.from(Array(size / 2), (e, i) => i + 1); // Fancy-pants way of making 1,2,3, . .
45 | let imIp = Float64Array.from(Array(size / 2), (e, i) => i + 1);
46 | imIp = imIp.map(x => x + 1);
47 |
48 | const oo = new Ooura(size, {type: 'complex', radix: 4});
49 | const reOp = new Float64Array(size / 2);
50 | const imOp = new Float64Array(size / 2);
51 | const result = new Object();
52 |
53 | oo.fft(reIp.buffer, imIp.buffer, reOp.buffer, imOp.buffer);
54 |
55 | result.reDiffsForwards = exports.CheckBuffers(reOp, reRef);
56 | result.imDiffsForwards = exports.CheckBuffers(imOp, imRef);
57 |
58 | const reBk = new Float64Array(size / 2);
59 | const imBk = new Float64Array(size / 2);
60 |
61 | oo.ifft(reOp.buffer, imOp.buffer, reBk.buffer, imBk.buffer);
62 | result.reDiffsBackwards = exports.CheckBuffers(reBk, reIp);
63 | result.imDiffsBackwards = exports.CheckBuffers(imBk, imIp);
64 |
65 | // Console.log(reBk)
66 | // console.log(imBk)
67 |
68 | return result;
69 | };
70 |
--------------------------------------------------------------------------------
/spec/readme-example-spec.js:
--------------------------------------------------------------------------------
1 | describe('For the readme example', () => {
2 | it('should actually work without crashing - REAL', () => {
3 | const ooura = require('../ooura.js');
4 |
5 | // Set up an input signal of size 8;
6 | const input = new Float64Array([1, 2, 3, 4, 1, 2, 3, 4]);
7 |
8 | // Set up the fft object and use a helper to generate an output array
9 | // of corrct length and type.
10 | const oo = new ooura(input.length);
11 | const output = oo.scalarArrayFactory();
12 |
13 | // Helper to get single sided complex arrays
14 | const re = oo.vectorArrayFactory();
15 | const im = oo.vectorArrayFactory();
16 |
17 | // Do some FFTing in both directions
18 | // note: reference underlying array buffers for in-place processing
19 | oo.fft(input.buffer, re.buffer, im.buffer); // Populates re and im from input
20 | oo.ifft(output.buffer, re.buffer, im.buffer); // Populates output from re and im
21 |
22 | // look at the results and intermediate representation
23 | /*
24 | console.log("ip = " + input);
25 | console.log("re = " + re);
26 | console.log("im = " + im);
27 | console.log("op = " + output);
28 | */
29 | });
30 |
31 | it('should actually work without crashing - COMPLEX', () => {
32 | const ooura = require('../ooura.js');
33 |
34 | // Set up an input signal real and imag components
35 | const reInput = new Float64Array([1, 2, 3, 4]);
36 | const imInput = new Float64Array([2, 3, 4, 5]);
37 |
38 | // Set up the fft object and the empty arrays for transform results
39 | const oo = new ooura(reInput.length * 2, {type: 'complex', radix: 4});
40 | const reOutput = new Float64Array(oo.size / 2);
41 | const imOutput = new Float64Array(oo.size / 2);
42 | const reBack = new Float64Array(oo.size / 2);
43 | const imBack = new Float64Array(oo.size / 2);
44 |
45 | // Do some FFTing in both directions
46 | // note: reference underlying array buffers for in-place processing
47 | oo.fft(reInput.buffer, imInput.buffer, reOutput.buffer, imOutput.buffer); // Populates re and im from input
48 | oo.ifft(reOutput.buffer, imOutput.buffer, reBack.buffer, imBack.buffer); // Populates output from re and im
49 |
50 | // look at the results and intermediate representation
51 | /* console.log("real input = " + reInput);
52 | console.log("imag input = " + imInput);
53 |
54 | console.log("re transformed = " + reOutput);
55 | console.log("im transformed = " + imOutput);
56 |
57 | console.log("re inverse transformed = " + reBack);
58 | console.log("im inverse transformed = " + imBack); */
59 | });
60 | });
61 |
--------------------------------------------------------------------------------
/spec/correctness-complex-spec.js:
--------------------------------------------------------------------------------
1 | const util = require('./TestUtils.js');
2 |
3 | describe('Function of the complex FFT routines', () => {
4 | it('should work for complex size 2', () => {
5 | const re = new Float64Array([3.0, -1.0]);
6 | const im = new Float64Array([5.0, -1.0]);
7 | expect(util.TestCorrectnessComplex(re, im)).toEqual({
8 | reDiffsForwards: 0,
9 | imDiffsForwards: 0,
10 | reDiffsBackwards: 0,
11 | imDiffsBackwards: 0
12 | });
13 | });
14 |
15 | it('should work for complex size 4', () => {
16 | const re = new Float64Array([10, -4, -2, 0]);
17 | const im = new Float64Array([14, 0, -2, -4]);
18 | expect(util.TestCorrectnessComplex(re, im)).toEqual({
19 | reDiffsForwards: 0,
20 | imDiffsForwards: 0,
21 | reDiffsBackwards: 0,
22 | imDiffsBackwards: 0
23 | });
24 | });
25 |
26 | it('should work for complex size 128', () => {
27 | const re = new Float64Array([8256, -2671.07096781333, -1366.74992799918, -931.626831510555, -713.802904806967, -582.898291435322, -495.452953946559, -432.841088327604, -385.749727496054, -349.004942362522, -319.502322161285, -295.266283603675, -274.979725372052, -257.730765076338, -242.868017439391, -229.913761135237, -218.509667991878, -208.381686523466, -199.316630883113, -191.146162709975, -183.735578354521, -176.975799686028, -170.777549157344, -165.067044349453, -159.782768810591, -154.873017823622, -150.29401046315, -146.008421122339, -141.98422563763, -138.19378606934, -134.613118446942, -131.221302159351, -128, -124.933065388859, -122.006218817225, -119.206779664431, -116.523442613034, -113.946090217852, -111.46563496141, -109.073885495363, -106.763432826835, -104.527553035364, -102.360123755643, -100.255552174742, -98.2087127008507, -96.2148927871548, -94.2697456570445, -92.3692488890154, -90.5096679918781, -88.6875242413517, -86.8995661641295, -85.1427441500374, -83.4141877508699, -81.7111852889865, -80.0311654522436, -78.3716805962963, -76.7303915122981, -75.1050534488228, -73.4935032024542, -71.8936471127513, -70.3034498148585, -68.7209236174368, -67.144118385246, -65.5711118149713, -64, -62.4288881850289, -60.855881614754, -59.2790763825633, -57.6965501851415, -56.1063528872487, -54.5064967975457, -52.8949465511772, -51.2696084877019, -49.6283194037037, -47.9688345477564, -46.2888147110135, -44.5858122491301, -42.8572558499626, -41.1004338358705, -39.3124757586483, -37.4903320081219, -35.6307511109848, -33.7302543429555, -31.7851072128451, -29.7912872991493, -27.744447825258, -25.6398762443569, -23.4724469646356, -21.2365671731648, -18.9261145046371, -16.5343650385897, -14.0539097821476, -11.4765573869657, -8.79322033556861, -5.99378118277463, -3.0669346111406, 0, 3.22130215935101, 6.61311844694239, 10.1937860693398, 13.9842256376305, 18.0084211223394, 22.2940104631501, 26.8730178236219, 31.7827688105913, 37.0670443494534, 42.7775491573444, 48.9757996860282, 55.7355783545209, 63.1461627099753, 71.3166308831131, 80.3816865234661, 90.5096679918781, 101.913761135237, 114.868017439391, 129.730765076338, 146.979725372053, 167.266283603676, 191.502322161285, 221.004942362522, 257.749727496054, 304.841088327604, 367.452953946559, 454.898291435322, 585.802904806967, 803.626831510555, 1238.74992799918, 2543.07096781333]);
28 | const im = new Float64Array([8384, 2543.07096781333, 1238.74992799918, 803.626831510555, 585.802904806967, 454.898291435322, 367.452953946559, 304.841088327604, 257.749727496054, 221.004942362522, 191.502322161285, 167.266283603675, 146.979725372052, 129.730765076337, 114.86801743939, 101.913761135237, 90.5096679918781, 80.3816865234662, 71.316630883113, 63.1461627099754, 55.7355783545209, 48.9757996860282, 42.7775491573445, 37.0670443494534, 31.7827688105913, 26.8730178236219, 22.2940104631501, 18.0084211223395, 13.9842256376305, 10.1937860693399, 6.61311844694251, 3.22130215935113, 0, -3.06693461114082, -5.99378118277451, -8.79322033556866, -11.4765573869657, -14.0539097821476, -16.5343650385897, -18.9261145046372, -21.2365671731649, -23.4724469646356, -25.6398762443569, -27.744447825258, -29.7912872991493, -31.7851072128451, -33.7302543429555, -35.6307511109846, -37.4903320081219, -39.3124757586482, -41.1004338358705, -42.8572558499626, -44.5858122491301, -46.2888147110135, -47.9688345477564, -49.6283194037037, -51.2696084877019, -52.8949465511772, -54.5064967975458, -56.1063528872487, -57.6965501851415, -59.2790763825633, -60.8558816147541, -62.4288881850288, -64, -65.5711118149713, -67.144118385246, -68.7209236174367, -70.3034498148586, -71.8936471127513, -73.4935032024543, -75.1050534488227, -76.7303915122981, -78.3716805962963, -80.0311654522435, -81.7111852889865, -83.4141877508699, -85.1427441500374, -86.8995661641295, -88.6875242413517, -90.5096679918781, -92.3692488890154, -94.2697456570445, -96.2148927871548, -98.2087127008507, -100.255552174742, -102.360123755643, -104.527553035364, -106.763432826835, -109.073885495363, -111.46563496141, -113.946090217852, -116.523442613034, -119.206779664431, -122.006218817225, -124.933065388859, -128, -131.221302159351, -134.613118446942, -138.19378606934, -141.98422563763, -146.008421122339, -150.29401046315, -154.873017823622, -159.782768810591, -165.067044349453, -170.777549157344, -176.975799686028, -183.735578354521, -191.146162709975, -199.316630883113, -208.381686523466, -218.509667991878, -229.913761135237, -242.868017439391, -257.730765076338, -274.979725372052, -295.266283603675, -319.502322161285, -349.004942362522, -385.749727496054, -432.841088327604, -495.452953946559, -582.898291435322, -713.802904806967, -931.626831510555, -1366.74992799918, -2671.07096781333]);
29 | expect(util.TestCorrectnessComplex(re, im)).toEqual({
30 | reDiffsForwards: 0,
31 | imDiffsForwards: 0,
32 | reDiffsBackwards: 0,
33 | imDiffsBackwards: 0
34 | });
35 | });
36 | });
37 |
--------------------------------------------------------------------------------
/ooura.js:
--------------------------------------------------------------------------------
1 | const assert = require('assert');
2 | const init = require('./init.js');
3 | const trans = require('./transform.js');
4 |
5 | class Ooura {
6 | constructor(size, info = {type: 'real', radix: 4}) {
7 | assert(Ooura.isPowerOf2(size));
8 |
9 | this.real = (info.type === 'real');
10 | if (!this.real) {
11 | assert(info.type === 'complex'); // Sanity
12 | }
13 |
14 | this.size = size;
15 | this.ip = new Int16Array(2 + Math.sqrt(size));
16 | this.w = new Float64Array(size / 2);
17 | this.internal = new Float64Array(size);
18 |
19 | init.makewt(size / 4, this.ip.buffer, this.w.buffer);
20 |
21 | // Perform additional modification if real
22 | if (this.real) {
23 | init.makect(size / 4, this.ip.buffer, this.w.buffer, size / 4);
24 | this.fft = this.fftReal;
25 | this.ifft = this.ifftReal;
26 | this.fftInPlace = this.fftInPlaceReal;
27 | this.ifftInPlace = this.ifftInPlaceReal;
28 | } else {
29 | this.fft = this.fftComplex;
30 | this.ifft = this.ifftComplex;
31 | this.fftInPlace = this.fftInPlaceComplex;
32 | this.ifftInPlace = this.ifftInPlaceComplex;
33 | }
34 | }
35 |
36 | // Returns complex vector size given one dimensional scalar size
37 | static vectorSize(scalarSize) {
38 | assert(Ooura.isPowerOf2(scalarSize));
39 | return (scalarSize / 2) + 1;
40 | }
41 |
42 | // Inverse fucntion of vector size
43 | static scalarSize(vectorSize) {
44 | const result = (vectorSize - 1) * 2;
45 | assert(Ooura.isPowerOf2(result));
46 | return result;
47 | }
48 |
49 | static isPowerOf2(n) {
50 | if (typeof n !== 'number') {
51 | return false;
52 | }
53 | return n && (n & (n - 1)) === 0;
54 | }
55 |
56 | getScalarSize() {
57 | return this.size;
58 | }
59 |
60 | getVectorSize() {
61 | return Ooura.vectorSize(this.size);
62 | }
63 |
64 | // Helper factory functions returning correct array and data size for a
65 | // given fft setup;
66 | scalarArrayFactory() {
67 | return new Float64Array(this.getScalarSize());
68 | }
69 |
70 | vectorArrayFactory() {
71 | return new Float64Array(this.getVectorSize());
72 | }
73 |
74 | // Functions below here should be called via their aliases defined in the ctor
75 | fftReal(dataBuffer, reBuffer, imBuffer) {
76 | const data = new Float64Array(dataBuffer);
77 | this.internal.set(data);
78 |
79 | trans.rdft(this.size, trans.DIRECTION.FORWARDS, this.internal.buffer, this.ip.buffer, this.w.buffer);
80 |
81 | const im = new Float64Array(imBuffer);
82 | const re = new Float64Array(reBuffer);
83 |
84 | // De-interleave data
85 | let nn = 0;
86 | let mm = 0;
87 | while (nn !== this.size) {
88 | re[nn] = this.internal[mm++];
89 | im[nn++] = -this.internal[mm++];
90 | }
91 |
92 | // Post cleanup
93 | re[this.size / 2] = -im[0];
94 | im[0] = 0.0;
95 | im[this.size / 2] = 0.0;
96 | }
97 |
98 | ifftReal(dataBuffer, reBuffer, imBuffer) {
99 | const im = new Float64Array(imBuffer);
100 | const re = new Float64Array(reBuffer);
101 |
102 | // Pack complex into buffer
103 | let nn = 0;
104 | let mm = 0;
105 | while (nn !== this.size) {
106 | this.internal[mm++] = re[nn];
107 | this.internal[mm++] = -im[nn++];
108 | }
109 | this.internal[1] = re[this.size / 2];
110 |
111 | trans.rdft(this.size, trans.DIRECTION.BACKWARDS, this.internal.buffer, this.ip.buffer, this.w.buffer);
112 |
113 | const data = new Float64Array(dataBuffer);
114 | data.set(this.internal.map(x => x * 2 / this.size));
115 | }
116 |
117 | xfftComplex(direction, reIpBuffer, imIpBuffer, reOpBuffer, imOpBuffer) {
118 | const reIp = new Float64Array(reIpBuffer);
119 | const imIp = new Float64Array(imIpBuffer);
120 | const reOp = new Float64Array(reOpBuffer);
121 | const imOp = new Float64Array(imOpBuffer);
122 |
123 | // Pack complex input into buffer
124 | let nn = 0;
125 | let mm = 0;
126 | while (nn !== this.size) {
127 | this.internal[mm++] = reIp[nn];
128 | this.internal[mm++] = -imIp[nn++];
129 | }
130 |
131 | trans.cdft(this.size, direction, this.internal.buffer, this.ip.buffer, this.w.buffer);
132 |
133 | // De-interleave data into output
134 | nn = 0;
135 | mm = 0;
136 | while (nn !== this.size) {
137 | reOp[nn] = this.internal[mm++];
138 | imOp[nn++] = -this.internal[mm++];
139 | }
140 | }
141 |
142 | fftComplex(reIpBuffer, imIpBuffer, reOpBuffer, imOpBuffer) {
143 | this.xfftComplex(trans.DIRECTION.FORWARDS, reIpBuffer, imIpBuffer, reOpBuffer, imOpBuffer);
144 | }
145 |
146 | ifftComplex(reIpBuffer, imIpBuffer, reOpBuffer, imOpBuffer) {
147 | this.xfftComplex(trans.DIRECTION.BACKWARDS, reIpBuffer, imIpBuffer, reOpBuffer, imOpBuffer);
148 | const reOp = new Float64Array(reOpBuffer);
149 | const imOp = new Float64Array(imOpBuffer);
150 | for (let nn = 0; nn < this.size / 2; ++nn) {
151 | reOp[nn] = reOp[nn] * 2 / this.size;
152 | imOp[nn] = imOp[nn] * 2 / this.size;
153 | }
154 | }
155 |
156 | // Below: No-nonsense thin wrappers around the interleaved in-place data
157 | // representation with no scaling, for maximum throughput.
158 | fftInPlaceReal(dataBuffer) {
159 | trans.rdft(this.size, trans.DIRECTION.FORWARDS, dataBuffer, this.ip.buffer, this.w.buffer);
160 | }
161 |
162 | fftInPlaceComplex(dataBuffer) {
163 | trans.cdft(this.size, trans.DIRECTION.FORWARDS, dataBuffer, this.ip.buffer, this.w.buffer);
164 | }
165 |
166 | ifftInPlaceReal(dataBuffer) {
167 | trans.rdft(this.size, trans.DIRECTION.BACKWARDS, dataBuffer, this.ip.buffer, this.w.buffer);
168 | }
169 |
170 | ifftInPlaceComplex(dataBuffer) {
171 | trans.cdft(this.size, trans.DIRECTION.BACKWARDS, dataBuffer, this.ip.buffer, this.w.buffer);
172 | }
173 |
174 | }
175 | module.exports = Ooura;
176 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Ooura FFT [](https://badge.fury.io/js/ooura)
2 | ===============================
3 |
4 | Ultra fast 1D real/complex FFT with simple interface.
5 |
6 | | Branch | Master | Develop |
7 | | :--- | :--- | :--- |
8 | | Circle CI
| [](https://circleci.com/gh/audioplastic/ooura) | [](https://circleci.com/gh/audioplastic/ooura) |
9 | | Appveyor
| [](https://ci.appveyor.com/project/audioplastic/ooura/branch/master)| [](https://ci.appveyor.com/project/audioplastic/ooura/branch/develop) |
10 | | Travis
| [](https://travis-ci.org/audioplastic/ooura) | [](https://travis-ci.org/audioplastic/ooura) |
11 | | Coveralls | [](https://coveralls.io/github/audioplastic/ooura?branch=master) | [](https://coveralls.io/github/audioplastic/ooura?branch=develop) |
12 |
13 | This is a dependency-free Javascript version of Takuya Ooura's FFT algorithms derived from the [C/Fortran FFT implementation](http://www.kurims.kyoto-u.ac.jp/~ooura/fft.html). I wanted a fast 1D FFT implementation in Javascript, and the Ooura implementation is a very portable and performant FFT implementation that lends itself well to a porting.
14 |
15 | ### Performance
16 | 
17 |
18 | For a wide range of useful FFT sizes, ooura has higher throughput than other Node FFT packages tested. There is still plenty of scope for optimisation road-mapped for future releases (radix-8, split radix). For details on benchmarking, see [this](https://github.com/audioplastic/fft-js-benchmark) dedicated repository.
19 |
20 | ### Correctness
21 | This implementation has been tested using power-of-2 FFT sizes against trusted reference values (however, I accept no responsibility if this trashes your app, or for any other damages). To test yourself, clone the repository from GitHub and run `npm install` to install (just to install the test runner), then run `npm test`.
22 |
23 | ### Usage: Real [](https://runkit.com/audioplastic/ooura-real)
24 | This implementation performs real FFT and inverse-FFT using double precision javascript `TypedArray`. Below is an example of typical extraction of the split-complex spectrum, and back conversion to real array.
25 |
26 | ```js
27 | var ooura = require('ooura');
28 |
29 | // Set up an input signal of size 8;
30 | let input = new Float64Array([1,2,3,4,1,2,3,4]);
31 |
32 | // Set up the FFT object and use a helper to generate an output array
33 | // of correct length and type.
34 | let oo = new ooura(input.length, {"type":"real", "radix":4});
35 | let output = oo.scalarArrayFactory();
36 |
37 | //helper to get single sided complex arrays
38 | let re = oo.vectorArrayFactory();
39 | let im = oo.vectorArrayFactory();
40 |
41 | //do some FFTing in both directions (using the built in helper functions to get senseful I/O)
42 | //note: reference underlying array buffers for in-place processing
43 | oo.fft(input.buffer, re.buffer, im.buffer); //populates re and im from input
44 | oo.ifft(output.buffer, re.buffer, im.buffer); //populates output from re and im
45 |
46 | // look at the results and intermediate representation
47 | console.log("ip = " + input);
48 | console.log("re = " + re);
49 | console.log("im = " + im);
50 | console.log("op = " + output);
51 | ```
52 |
53 | ### Usage: complex [](https://runkit.com/audioplastic/ooura-real)
54 | Complex FFT is also possible with this package. Simply initialise the FFT object specifying a complex type FFT.
55 |
56 | ```js
57 | var ooura = require('ooura');
58 |
59 | // Set up an input signal real and imag components
60 | let reInput = new Float64Array([1,2,3,4]);
61 | let imInput = new Float64Array([2,3,4,5]);
62 |
63 | // Set up the fft object and the empty arrays for transform results
64 | let oo = new ooura(reInput.length*2, {"type":"complex", "radix":4});
65 | let reOutput = new Float64Array(oo.size/2);
66 | let imOutput = new Float64Array(oo.size/2);
67 | let reBack = new Float64Array(oo.size/2);
68 | let imBack = new Float64Array(oo.size/2);
69 |
70 | //do some FFTing in both directions
71 | //note: reference underlying array buffers for in-place processing
72 | oo.fft(reInput.buffer, imInput.buffer, reOutput.buffer, imOutput.buffer); //populates re and im from input
73 | oo.ifft(reOutput.buffer, imOutput.buffer, reBack.buffer, imBack.buffer); //populates output from re and im
74 |
75 | // look at the results and intermediate representation
76 | console.log("real input = " + reInput);
77 | console.log("imag input = " + imInput);
78 |
79 | console.log("re transformed = " + reOutput);
80 | console.log("im transformed = " + imOutput);
81 |
82 | console.log("re inverse transformed = " + reBack);
83 | console.log("im inverse transformed = " + imBack);
84 | ```
85 |
86 | ### Usage: in-place (real/complex) [](https://runkit.com/audioplastic/ooura-in-place)
87 | For the ultimate throughput, there are thin wrapper functions around the underlying FFT implementation that performs operations in place on interleaved complex or real buffers. The following example shows the complex FFT forwards and back, outputting the state of the data at each step to the console.
88 |
89 | ```js
90 | var ooura = require('ooura');
91 | const nfft = 32;
92 | let oo = new ooura(nfft, {"type":"complex", "radix":4} );
93 | let data = Float64Array.from(Array(nfft), (e,i)=>i+1);
94 | console.log(data);
95 | oo.fftInPlace(data.buffer);
96 | console.log(data);
97 | oo.ifftInPlace(data.buffer);
98 | console.log(data); // Notice the fast in-place methods do not scale the output
99 | console.log(data.map(x=>x*2/oo.size)); // ... but that is simple to do manually
100 | ```
101 |
102 | ### Coding Style [](https://github.com/sindresorhus/xo)
103 | The codebase is linted during testing using [XO](https://github.com/sindresorhus/xo), but with 2 overrides:
104 | 1) `no-mixed-operators` is disabled. Conventional [XO](https://github.com/sindresorhus/xo) linting requires only one type of arithmetic operator per command unless each operator is explicitly separated using parentheses. For DSP code, this causes a lot of unnecessary verbosity. If you're an engineer with a grasp of the basic order of operations (BODMAS), then redundant parentheses are bad style.
105 | 2) `one-var` is disabled. I understand the reasoning for this rule, but this code is ported from C, where a common idiom is to declare all variables at the top of each function. Disabling this rule allows the JS and C versions of the code to be more easily comparable.
106 |
107 | The spec folder is also excluded from XO linting as part of `npm test` due to errors raised in relation to the way that the Jasmine test framework operated. However, it is still recommended to manually run `xo --fix spec/*` after modifying unit tests to maintain a level of consistency.
108 |
--------------------------------------------------------------------------------
/spec/correctness-real-spec.js:
--------------------------------------------------------------------------------
1 | // Tests here inspired by HiFi-LoFi's AudioFFT tests
2 | // https://github.com/HiFi-LoFi/AudioFFT
3 | //
4 | // I increased the accuracy of some of the test references to get better tolerance
5 |
6 | const util = require('./TestUtils.js');
7 |
8 | describe('Function of the FFT routines', () => {
9 | it('should pass testing of the test helper function \'CheckBuffers\'', () => {
10 | expect(util.CheckBuffers([1, 2, 3, 4], [1, 2, 3, 4])).toEqual(0);
11 | expect(util.CheckBuffers([1, 2, 3, 4], [1, 2.2, 3, 4.2])).toEqual(2);
12 | });
13 |
14 | it('should work for real size 2', () => {
15 | const re = new Float64Array([3.0000000, -1.0000000]);
16 | const im = new Float64Array([0.00000000, 0.00000000]);
17 | expect(util.TestCorrectnessReal(re, im)).toEqual({
18 | reDiffs: 0,
19 | imDiffs: 0,
20 | reverseDiffs: 0
21 | });
22 | });
23 |
24 | it('should work for real size 4', () => {
25 | const re = new Float64Array([10.000000, -2.0000000, -2.0000000]);
26 | const im = new Float64Array([0.00000000, 2.0000000, 0.00000000]);
27 | expect(util.TestCorrectnessReal(re, im)).toEqual({
28 | reDiffs: 0,
29 | imDiffs: 0,
30 | reverseDiffs: 0
31 | });
32 | });
33 |
34 | it('should work for real size 8', () => {
35 | const re = new Float64Array([36.000000, -4.0000000, -4.0000000, -4.0000000, -4.0000000]);
36 | const im = new Float64Array([0, 9.65685424949238, 4, 1.65685424949238, 0]);
37 | expect(util.TestCorrectnessReal(re, im)).toEqual({
38 | reDiffs: 0,
39 | imDiffs: 0,
40 | reverseDiffs: 0
41 | });
42 | });
43 |
44 | it('should work for real size 16', () => {
45 | const re = new Float64Array([136.00000, -8.0000000, -8.0000000, -8.0000000, -8.0000000, -8.0000000, -8.0000000, -8.0000000, -8.0000000]);
46 | const im = new Float64Array([0, 40.2187159370068, 19.3137084989848, 11.9728461013239, 8, 5.34542910335439, 3.31370849898476, 1.59129893903727, 0]);
47 | expect(util.TestCorrectnessReal(re, im)).toEqual({
48 | reDiffs: 0,
49 | imDiffs: 0,
50 | reverseDiffs: 0
51 | });
52 | });
53 |
54 | it('should work for real size 32', () => {
55 | const re = new Float64Array([528.00000, -16.000000, -16.000000, -16.000000, -16.000000, -16.000000, -16.000000, -16.000000, -16.000000, -16.000000, -16.000000, -16.000000, -16.000000, -16.000000, -16.000000, -16.000000, -16.000000]);
56 | const im = new Float64Array([0, 162.450726201742, 80.4374318740136, 52.7449313430131, 38.6274169979695, 29.9338945886302, 23.9456922026478, 19.4960564094076, 16, 13.1308606532586, 10.6908582067088, 8.55217817521267, 6.62741699796952, 4.85354693771748, 3.18259787807452, 1.57586245371462, 0]);
57 | expect(util.TestCorrectnessReal(re, im)).toEqual({
58 | reDiffs: 0,
59 | imDiffs: 0,
60 | reverseDiffs: 0
61 | });
62 | });
63 |
64 | it('should work for real size 64', () => {
65 | const re = new Float64Array([2080, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32]);
66 | const im = new Float64Array([0, 651.37496399959, 324.901452403484, 215.72647697328, 160.874863748027, 127.751161080643, 105.489862686026, 89.4340087196953, 77.254833995939, 67.6583154415565, 59.8677891772604, 53.3887745786722, 47.8913844052957, 43.147005231575, 38.9921128188153, 35.3065592234712, 32, 29.0031094086127, 26.2617213065171, 23.7328174807051, 21.3817164134176, 19.1800618778216, 17.1043563504253, 15.1348728285222, 13.254833995939, 11.4497830820648, 9.70709387543495, 8.01558272612178, 6.36519575614905, 4.74675160122712, 3.15172490742924, 1.57205919262293, 0]);
67 | expect(util.TestCorrectnessReal(re, im)).toEqual({
68 | reDiffs: 0,
69 | imDiffs: 0,
70 | reverseDiffs: 0
71 | });
72 | });
73 |
74 | it('should work for real size 128', () => {
75 | const re = new Float64Array([8256.0000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000, -64.000000]);
76 | const im = new Float64Array([0, 2607.07096781333, 1302.74992799918, 867.626831510555, 649.802904806967, 518.898291435322, 431.452953946559, 368.841088327604, 321.749727496054, 285.004942362522, 255.502322161285, 231.266283603675, 210.979725372053, 193.730765076338, 178.86801743939, 165.913761135237, 154.509667991878, 144.381686523466, 135.316630883113, 127.146162709975, 119.735578354521, 112.975799686028, 106.777549157344, 101.067044349453, 95.7827688105913, 90.8730178236219, 86.2940104631501, 82.0084211223395, 77.9842256376305, 74.1937860693399, 70.6131184469425, 67.2213021593511, 64, 60.9330653888591, 58.0062188172253, 55.2067796644313, 52.5234426130342, 49.9460902178524, 47.4656349614103, 45.0738854953628, 42.7634328268351, 40.5275530353644, 38.3601237556431, 36.255552174742, 34.2087127008507, 32.2148927871548, 30.2697456570445, 28.3692488890153, 26.5096679918781, 24.6875242413518, 22.8995661641296, 21.1427441500374, 19.41418775087, 17.7111852889865, 16.0311654522436, 14.3716805962963, 12.7303915122981, 11.1050534488228, 9.49350320245426, 7.8936471127513, 6.30344981485854, 4.72092361743671, 3.14411838524597, 1.57111181497135, 0]);
77 | expect(util.TestCorrectnessReal(re, im)).toEqual({
78 | reDiffs: 0,
79 | imDiffs: 0,
80 | reverseDiffs: 0
81 | });
82 | });
83 |
84 | it('should work for real size 256', () => {
85 | const re = new Float64Array([32896.000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000, -128.00000]);
86 | const im = new Float64Array([0, 10429.8547464379, 5214.14193562666, 3475.22184520956, 2605.49985599836, 2083.45701887173, 1735.25366302111, 1486.38705426371, 1299.60580961393, 1154.21470213437, 1037.79658287064, 942.449618089503, 862.905907893118, 795.518434699397, 737.682176655208, 687.486775680477, 643.499454992108, 604.624553968934, 570.009884725045, 538.982660288358, 511.004644322571, 485.640115211302, 462.532567207351, 441.387489540227, 421.959450744105, 404.042282744421, 387.461530152675, 372.068577493188, 357.736034878781, 344.354078371791, 331.827522270473, 320.073458047265, 309.019335983756, 298.601395596973, 288.763373046932, 279.455430129171, 270.633261766226, 262.257348227936, 254.292325419951, 246.706452048648, 239.471156709042, 232.560651250227, 225.951599372057, 219.622831461845, 213.555098314689, 207.730857688762, 202.134088698907, 196.750129902321, 191.565537621183, 186.567961611149, 181.746035647244, 177.089280979568, 172.5880209263, 168.233305132938, 164.016842244679, 159.930939921098, 155.968451275261, 152.12272694822, 148.38757213868, 144.75720799985, 141.226236893885, 137.789611061154, 134.442604318702, 131.180786451229, 128, 124.896339191344, 121.866130777718, 118.905916591407, 116.012437634451, 113.182619548845, 110.413559328863, 107.702513152929, 105.046885226068, 102.444217535913, 99.8921804357048, 97.388563976992, 94.9312699228205, 92.5183043794183, 90.1477709907257, 87.8178646457428, 85.5268656536703, 83.2731343462593, 81.0551060707287, 78.8712865401428, 76.7202475112863, 74.6006227628769, 72.511104349484, 70.4504391087697, 68.4174254017013, 66.410910067197, 64.4297855743098, 62.4729873565265, 60.539491314089, 58.6283114714461, 56.7384977780309, 54.8691340415361, 53.0193359837562, 51.1882494098607, 49.3750484827034, 47.5789340944311, 45.7991323282591, 44.0348930038305, 42.2854883000747, 40.5502114499332, 38.8283755017398, 37.1193121424136, 35.4223705779731, 33.7369164671896, 32.0623309044871, 30.398009448457, 28.7433611925924, 27.0978078750701, 25.4607830245962, 23.8317311395307, 22.2101068976455, 20.5953743940466, 18.9870064049085, 17.3844836748016, 15.7872942255025, 14.1949326842768, 12.606899629717, 11.0227009532963, 9.44184723487351, 7.863853130444, 6.28823677049195, 4.71451916734009, 3.14222362994269, 1.5708751845832, 0]);
87 | expect(util.TestCorrectnessReal(re, im)).toEqual({
88 | reDiffs: 0,
89 | imDiffs: 0,
90 | reverseDiffs: 0
91 | });
92 | });
93 | });
94 |
--------------------------------------------------------------------------------
/child.js:
--------------------------------------------------------------------------------
1 | exports.bitrv2 = function (n, ipBuffer, ipOffset, aBuffer) {
2 | let j, j1, k, k1, l, m;
3 | let xr, xi, yr, yi;
4 |
5 | // Create some views on the raw buffers
6 | const ip = new Int16Array(ipBuffer).subarray(ipOffset);
7 | const a = new Float64Array(aBuffer);
8 |
9 | ip[0] = 0;
10 | l = n;
11 | m = 1;
12 | while ((m << 3) < l) {
13 | l >>= 1;
14 | for (j = 0; j < m; j++) {
15 | ip[m + j] = ip[j] + l;
16 | }
17 | m <<= 1;
18 | }
19 | const m2 = 2 * m;
20 | if ((m << 3) === l) {
21 | for (k = 0; k < m; k++) {
22 | for (j = 0; j < k; j++) {
23 | j1 = 2 * j + ip[k];
24 | k1 = 2 * k + ip[j];
25 | xr = a[j1];
26 | xi = a[j1 + 1];
27 | yr = a[k1];
28 | yi = a[k1 + 1];
29 | a[j1] = yr;
30 | a[j1 + 1] = yi;
31 | a[k1] = xr;
32 | a[k1 + 1] = xi;
33 | j1 += m2;
34 | k1 += 2 * m2;
35 | xr = a[j1];
36 | xi = a[j1 + 1];
37 | yr = a[k1];
38 | yi = a[k1 + 1];
39 | a[j1] = yr;
40 | a[j1 + 1] = yi;
41 | a[k1] = xr;
42 | a[k1 + 1] = xi;
43 | j1 += m2;
44 | k1 -= m2;
45 | xr = a[j1];
46 | xi = a[j1 + 1];
47 | yr = a[k1];
48 | yi = a[k1 + 1];
49 | a[j1] = yr;
50 | a[j1 + 1] = yi;
51 | a[k1] = xr;
52 | a[k1 + 1] = xi;
53 | j1 += m2;
54 | k1 += 2 * m2;
55 | xr = a[j1];
56 | xi = a[j1 + 1];
57 | yr = a[k1];
58 | yi = a[k1 + 1];
59 | a[j1] = yr;
60 | a[j1 + 1] = yi;
61 | a[k1] = xr;
62 | a[k1 + 1] = xi;
63 | }
64 | j1 = 2 * k + m2 + ip[k];
65 | k1 = j1 + m2;
66 | xr = a[j1];
67 | xi = a[j1 + 1];
68 | yr = a[k1];
69 | yi = a[k1 + 1];
70 | a[j1] = yr;
71 | a[j1 + 1] = yi;
72 | a[k1] = xr;
73 | a[k1 + 1] = xi;
74 | }
75 | } else {
76 | for (k = 1; k < m; k++) {
77 | for (j = 0; j < k; j++) {
78 | j1 = 2 * j + ip[k];
79 | k1 = 2 * k + ip[j];
80 | xr = a[j1];
81 | xi = a[j1 + 1];
82 | yr = a[k1];
83 | yi = a[k1 + 1];
84 | a[j1] = yr;
85 | a[j1 + 1] = yi;
86 | a[k1] = xr;
87 | a[k1 + 1] = xi;
88 | j1 += m2;
89 | k1 += m2;
90 | xr = a[j1];
91 | xi = a[j1 + 1];
92 | yr = a[k1];
93 | yi = a[k1 + 1];
94 | a[j1] = yr;
95 | a[j1 + 1] = yi;
96 | a[k1] = xr;
97 | a[k1 + 1] = xi;
98 | }
99 | }
100 | }
101 | };
102 |
103 | exports.bitrv2conj = function (n, ipBuffer, ipOffset, aBuffer) {
104 | let j, j1, k, k1, l, m;
105 | let xr, xi, yr, yi;
106 |
107 | const ip = new Int16Array(ipBuffer).subarray(ipOffset);
108 | const a = new Float64Array(aBuffer);
109 |
110 | ip[0] = 0;
111 | l = n;
112 | m = 1;
113 | while ((m << 3) < l) {
114 | l >>= 1;
115 | for (j = 0; j < m; j++) {
116 | ip[m + j] = ip[j] + l;
117 | }
118 | m <<= 1;
119 | }
120 | const m2 = 2 * m;
121 | if ((m << 3) === l) {
122 | for (k = 0; k < m; k++) {
123 | for (j = 0; j < k; j++) {
124 | j1 = 2 * j + ip[k];
125 | k1 = 2 * k + ip[j];
126 | xr = a[j1];
127 | xi = -a[j1 + 1];
128 | yr = a[k1];
129 | yi = -a[k1 + 1];
130 | a[j1] = yr;
131 | a[j1 + 1] = yi;
132 | a[k1] = xr;
133 | a[k1 + 1] = xi;
134 | j1 += m2;
135 | k1 += 2 * m2;
136 | xr = a[j1];
137 | xi = -a[j1 + 1];
138 | yr = a[k1];
139 | yi = -a[k1 + 1];
140 | a[j1] = yr;
141 | a[j1 + 1] = yi;
142 | a[k1] = xr;
143 | a[k1 + 1] = xi;
144 | j1 += m2;
145 | k1 -= m2;
146 | xr = a[j1];
147 | xi = -a[j1 + 1];
148 | yr = a[k1];
149 | yi = -a[k1 + 1];
150 | a[j1] = yr;
151 | a[j1 + 1] = yi;
152 | a[k1] = xr;
153 | a[k1 + 1] = xi;
154 | j1 += m2;
155 | k1 += 2 * m2;
156 | xr = a[j1];
157 | xi = -a[j1 + 1];
158 | yr = a[k1];
159 | yi = -a[k1 + 1];
160 | a[j1] = yr;
161 | a[j1 + 1] = yi;
162 | a[k1] = xr;
163 | a[k1 + 1] = xi;
164 | }
165 | k1 = 2 * k + ip[k];
166 | a[k1 + 1] = -a[k1 + 1];
167 | j1 = k1 + m2;
168 | k1 = j1 + m2;
169 | xr = a[j1];
170 | xi = -a[j1 + 1];
171 | yr = a[k1];
172 | yi = -a[k1 + 1];
173 | a[j1] = yr;
174 | a[j1 + 1] = yi;
175 | a[k1] = xr;
176 | a[k1 + 1] = xi;
177 | k1 += m2;
178 | a[k1 + 1] = -a[k1 + 1];
179 | }
180 | } else {
181 | a[1] = -a[1];
182 | a[m2 + 1] = -a[m2 + 1];
183 | for (k = 1; k < m; k++) {
184 | for (j = 0; j < k; j++) {
185 | j1 = 2 * j + ip[k];
186 | k1 = 2 * k + ip[j];
187 | xr = a[j1];
188 | xi = -a[j1 + 1];
189 | yr = a[k1];
190 | yi = -a[k1 + 1];
191 | a[j1] = yr;
192 | a[j1 + 1] = yi;
193 | a[k1] = xr;
194 | a[k1 + 1] = xi;
195 | j1 += m2;
196 | k1 += m2;
197 | xr = a[j1];
198 | xi = -a[j1 + 1];
199 | yr = a[k1];
200 | yi = -a[k1 + 1];
201 | a[j1] = yr;
202 | a[j1 + 1] = yi;
203 | a[k1] = xr;
204 | a[k1 + 1] = xi;
205 | }
206 | k1 = 2 * k + ip[k];
207 | a[k1 + 1] = -a[k1 + 1];
208 | a[k1 + m2 + 1] = -a[k1 + m2 + 1];
209 | }
210 | }
211 | };
212 |
213 | const cftmdl = function (n, l, aBuffer, wBuffer) {
214 | let j, j1, j2, j3, k, k1, k2;
215 | let wk1r, wk1i, wk2r, wk2i, wk3r, wk3i;
216 | let x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i;
217 |
218 | const a = new Float64Array(aBuffer);
219 | const w = new Float64Array(wBuffer);
220 |
221 | const m = l << 2;
222 | for (j = 0; j < l; j += 2) {
223 | j1 = j + l;
224 | j2 = j1 + l;
225 | j3 = j2 + l;
226 | x0r = a[j] + a[j1];
227 | x0i = a[j + 1] + a[j1 + 1];
228 | x1r = a[j] - a[j1];
229 | x1i = a[j + 1] - a[j1 + 1];
230 | x2r = a[j2] + a[j3];
231 | x2i = a[j2 + 1] + a[j3 + 1];
232 | x3r = a[j2] - a[j3];
233 | x3i = a[j2 + 1] - a[j3 + 1];
234 | a[j] = x0r + x2r;
235 | a[j + 1] = x0i + x2i;
236 | a[j2] = x0r - x2r;
237 | a[j2 + 1] = x0i - x2i;
238 | a[j1] = x1r - x3i;
239 | a[j1 + 1] = x1i + x3r;
240 | a[j3] = x1r + x3i;
241 | a[j3 + 1] = x1i - x3r;
242 | }
243 | wk1r = w[2];
244 | for (j = m; j < l + m; j += 2) {
245 | j1 = j + l;
246 | j2 = j1 + l;
247 | j3 = j2 + l;
248 | x0r = a[j] + a[j1];
249 | x0i = a[j + 1] + a[j1 + 1];
250 | x1r = a[j] - a[j1];
251 | x1i = a[j + 1] - a[j1 + 1];
252 | x2r = a[j2] + a[j3];
253 | x2i = a[j2 + 1] + a[j3 + 1];
254 | x3r = a[j2] - a[j3];
255 | x3i = a[j2 + 1] - a[j3 + 1];
256 | a[j] = x0r + x2r;
257 | a[j + 1] = x0i + x2i;
258 | a[j2] = x2i - x0i;
259 | a[j2 + 1] = x0r - x2r;
260 | x0r = x1r - x3i;
261 | x0i = x1i + x3r;
262 | a[j1] = wk1r * (x0r - x0i);
263 | a[j1 + 1] = wk1r * (x0r + x0i);
264 | x0r = x3i + x1r;
265 | x0i = x3r - x1i;
266 | a[j3] = wk1r * (x0i - x0r);
267 | a[j3 + 1] = wk1r * (x0i + x0r);
268 | }
269 | k1 = 0;
270 | const m2 = 2 * m;
271 | for (k = m2; k < n; k += m2) {
272 | k1 += 2;
273 | k2 = 2 * k1;
274 | wk2r = w[k1];
275 | wk2i = w[k1 + 1];
276 | wk1r = w[k2];
277 | wk1i = w[k2 + 1];
278 | wk3r = wk1r - 2 * wk2i * wk1i;
279 | wk3i = 2 * wk2i * wk1r - wk1i;
280 | for (j = k; j < l + k; j += 2) {
281 | j1 = j + l;
282 | j2 = j1 + l;
283 | j3 = j2 + l;
284 | x0r = a[j] + a[j1];
285 | x0i = a[j + 1] + a[j1 + 1];
286 | x1r = a[j] - a[j1];
287 | x1i = a[j + 1] - a[j1 + 1];
288 | x2r = a[j2] + a[j3];
289 | x2i = a[j2 + 1] + a[j3 + 1];
290 | x3r = a[j2] - a[j3];
291 | x3i = a[j2 + 1] - a[j3 + 1];
292 | a[j] = x0r + x2r;
293 | a[j + 1] = x0i + x2i;
294 | x0r -= x2r;
295 | x0i -= x2i;
296 | a[j2] = wk2r * x0r - wk2i * x0i;
297 | a[j2 + 1] = wk2r * x0i + wk2i * x0r;
298 | x0r = x1r - x3i;
299 | x0i = x1i + x3r;
300 | a[j1] = wk1r * x0r - wk1i * x0i;
301 | a[j1 + 1] = wk1r * x0i + wk1i * x0r;
302 | x0r = x1r + x3i;
303 | x0i = x1i - x3r;
304 | a[j3] = wk3r * x0r - wk3i * x0i;
305 | a[j3 + 1] = wk3r * x0i + wk3i * x0r;
306 | }
307 | wk1r = w[k2 + 2];
308 | wk1i = w[k2 + 3];
309 | wk3r = wk1r - 2 * wk2r * wk1i;
310 | wk3i = 2 * wk2r * wk1r - wk1i;
311 | for (j = k + m; j < l + (k + m); j += 2) {
312 | j1 = j + l;
313 | j2 = j1 + l;
314 | j3 = j2 + l;
315 | x0r = a[j] + a[j1];
316 | x0i = a[j + 1] + a[j1 + 1];
317 | x1r = a[j] - a[j1];
318 | x1i = a[j + 1] - a[j1 + 1];
319 | x2r = a[j2] + a[j3];
320 | x2i = a[j2 + 1] + a[j3 + 1];
321 | x3r = a[j2] - a[j3];
322 | x3i = a[j2 + 1] - a[j3 + 1];
323 | a[j] = x0r + x2r;
324 | a[j + 1] = x0i + x2i;
325 | x0r -= x2r;
326 | x0i -= x2i;
327 | a[j2] = -wk2i * x0r - wk2r * x0i;
328 | a[j2 + 1] = -wk2i * x0i + wk2r * x0r;
329 | x0r = x1r - x3i;
330 | x0i = x1i + x3r;
331 | a[j1] = wk1r * x0r - wk1i * x0i;
332 | a[j1 + 1] = wk1r * x0i + wk1i * x0r;
333 | x0r = x1r + x3i;
334 | x0i = x1i - x3r;
335 | a[j3] = wk3r * x0r - wk3i * x0i;
336 | a[j3 + 1] = wk3r * x0i + wk3i * x0r;
337 | }
338 | }
339 | };
340 |
341 | const cft1st = function (n, aBuffer, wBuffer) {
342 | let j, k1, k2;
343 | let wk1r, wk1i, wk2r, wk2i, wk3r, wk3i;
344 | let x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i;
345 |
346 | const a = new Float64Array(aBuffer);
347 | const w = new Float64Array(wBuffer);
348 |
349 | x0r = a[0] + a[2];
350 | x0i = a[1] + a[3];
351 | x1r = a[0] - a[2];
352 | x1i = a[1] - a[3];
353 | x2r = a[4] + a[6];
354 | x2i = a[5] + a[7];
355 | x3r = a[4] - a[6];
356 | x3i = a[5] - a[7];
357 | a[0] = x0r + x2r;
358 | a[1] = x0i + x2i;
359 | a[4] = x0r - x2r;
360 | a[5] = x0i - x2i;
361 | a[2] = x1r - x3i;
362 | a[3] = x1i + x3r;
363 | a[6] = x1r + x3i;
364 | a[7] = x1i - x3r;
365 | wk1r = w[2];
366 | x0r = a[8] + a[10];
367 | x0i = a[9] + a[11];
368 | x1r = a[8] - a[10];
369 | x1i = a[9] - a[11];
370 | x2r = a[12] + a[14];
371 | x2i = a[13] + a[15];
372 | x3r = a[12] - a[14];
373 | x3i = a[13] - a[15];
374 | a[8] = x0r + x2r;
375 | a[9] = x0i + x2i;
376 | a[12] = x2i - x0i;
377 | a[13] = x0r - x2r;
378 | x0r = x1r - x3i;
379 | x0i = x1i + x3r;
380 | a[10] = wk1r * (x0r - x0i);
381 | a[11] = wk1r * (x0r + x0i);
382 | x0r = x3i + x1r;
383 | x0i = x3r - x1i;
384 | a[14] = wk1r * (x0i - x0r);
385 | a[15] = wk1r * (x0i + x0r);
386 | k1 = 0;
387 | for (j = 16; j < n; j += 16) {
388 | k1 += 2;
389 | k2 = 2 * k1;
390 | wk2r = w[k1];
391 | wk2i = w[k1 + 1];
392 | wk1r = w[k2];
393 | wk1i = w[k2 + 1];
394 | wk3r = wk1r - 2 * wk2i * wk1i;
395 | wk3i = 2 * wk2i * wk1r - wk1i;
396 | x0r = a[j] + a[j + 2];
397 | x0i = a[j + 1] + a[j + 3];
398 | x1r = a[j] - a[j + 2];
399 | x1i = a[j + 1] - a[j + 3];
400 | x2r = a[j + 4] + a[j + 6];
401 | x2i = a[j + 5] + a[j + 7];
402 | x3r = a[j + 4] - a[j + 6];
403 | x3i = a[j + 5] - a[j + 7];
404 | a[j] = x0r + x2r;
405 | a[j + 1] = x0i + x2i;
406 | x0r -= x2r;
407 | x0i -= x2i;
408 | a[j + 4] = wk2r * x0r - wk2i * x0i;
409 | a[j + 5] = wk2r * x0i + wk2i * x0r;
410 | x0r = x1r - x3i;
411 | x0i = x1i + x3r;
412 | a[j + 2] = wk1r * x0r - wk1i * x0i;
413 | a[j + 3] = wk1r * x0i + wk1i * x0r;
414 | x0r = x1r + x3i;
415 | x0i = x1i - x3r;
416 | a[j + 6] = wk3r * x0r - wk3i * x0i;
417 | a[j + 7] = wk3r * x0i + wk3i * x0r;
418 | wk1r = w[k2 + 2];
419 | wk1i = w[k2 + 3];
420 | wk3r = wk1r - 2 * wk2r * wk1i;
421 | wk3i = 2 * wk2r * wk1r - wk1i;
422 | x0r = a[j + 8] + a[j + 10];
423 | x0i = a[j + 9] + a[j + 11];
424 | x1r = a[j + 8] - a[j + 10];
425 | x1i = a[j + 9] - a[j + 11];
426 | x2r = a[j + 12] + a[j + 14];
427 | x2i = a[j + 13] + a[j + 15];
428 | x3r = a[j + 12] - a[j + 14];
429 | x3i = a[j + 13] - a[j + 15];
430 | a[j + 8] = x0r + x2r;
431 | a[j + 9] = x0i + x2i;
432 | x0r -= x2r;
433 | x0i -= x2i;
434 | a[j + 12] = -wk2i * x0r - wk2r * x0i;
435 | a[j + 13] = -wk2i * x0i + wk2r * x0r;
436 | x0r = x1r - x3i;
437 | x0i = x1i + x3r;
438 | a[j + 10] = wk1r * x0r - wk1i * x0i;
439 | a[j + 11] = wk1r * x0i + wk1i * x0r;
440 | x0r = x1r + x3i;
441 | x0i = x1i - x3r;
442 | a[j + 14] = wk3r * x0r - wk3i * x0i;
443 | a[j + 15] = wk3r * x0i + wk3i * x0r;
444 | }
445 | };
446 |
447 | exports.cftfsub = function (n, aBuffer, wBuffer) {
448 | let j, j1, j2, j3, l;
449 | let x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i;
450 |
451 | // Create some views on the raw buffers
452 | const a = new Float64Array(aBuffer);
453 | const w = new Float64Array(wBuffer);
454 |
455 | l = 2;
456 | if (n > 8) {
457 | cft1st(n, a.buffer, w.buffer);
458 | l = 8;
459 | while ((l << 2) < n) {
460 | cftmdl(n, l, a.buffer, w.buffer);
461 | l <<= 2;
462 | }
463 | }
464 | if ((l << 2) === n) {
465 | for (j = 0; j < l; j += 2) {
466 | j1 = j + l;
467 | j2 = j1 + l;
468 | j3 = j2 + l;
469 | x0r = a[j] + a[j1];
470 | x0i = a[j + 1] + a[j1 + 1];
471 | x1r = a[j] - a[j1];
472 | x1i = a[j + 1] - a[j1 + 1];
473 | x2r = a[j2] + a[j3];
474 | x2i = a[j2 + 1] + a[j3 + 1];
475 | x3r = a[j2] - a[j3];
476 | x3i = a[j2 + 1] - a[j3 + 1];
477 | a[j] = x0r + x2r;
478 | a[j + 1] = x0i + x2i;
479 | a[j2] = x0r - x2r;
480 | a[j2 + 1] = x0i - x2i;
481 | a[j1] = x1r - x3i;
482 | a[j1 + 1] = x1i + x3r;
483 | a[j3] = x1r + x3i;
484 | a[j3 + 1] = x1i - x3r;
485 | }
486 | } else {
487 | for (j = 0; j < l; j += 2) {
488 | j1 = j + l;
489 | x0r = a[j] - a[j1];
490 | x0i = a[j + 1] - a[j1 + 1];
491 | a[j] += a[j1];
492 | a[j + 1] += a[j1 + 1];
493 | a[j1] = x0r;
494 | a[j1 + 1] = x0i;
495 | }
496 | }
497 | };
498 |
499 | exports.cftbsub = function (n, aBuffer, wBuffer) {
500 | let j, j1, j2, j3, l;
501 | let x0r, x0i, x1r, x1i, x2r, x2i, x3r, x3i;
502 |
503 | const a = new Float64Array(aBuffer);
504 | const w = new Float64Array(wBuffer);
505 |
506 | l = 2;
507 | if (n > 8) {
508 | cft1st(n, a.buffer, w.buffer);
509 | l = 8;
510 | while ((l << 2) < n) {
511 | cftmdl(n, l, a.buffer, w.buffer);
512 | l <<= 2;
513 | }
514 | }
515 | if ((l << 2) === n) {
516 | for (j = 0; j < l; j += 2) {
517 | j1 = j + l;
518 | j2 = j1 + l;
519 | j3 = j2 + l;
520 | x0r = a[j] + a[j1];
521 | x0i = -a[j + 1] - a[j1 + 1];
522 | x1r = a[j] - a[j1];
523 | x1i = -a[j + 1] + a[j1 + 1];
524 | x2r = a[j2] + a[j3];
525 | x2i = a[j2 + 1] + a[j3 + 1];
526 | x3r = a[j2] - a[j3];
527 | x3i = a[j2 + 1] - a[j3 + 1];
528 | a[j] = x0r + x2r;
529 | a[j + 1] = x0i - x2i;
530 | a[j2] = x0r - x2r;
531 | a[j2 + 1] = x0i + x2i;
532 | a[j1] = x1r - x3i;
533 | a[j1 + 1] = x1i - x3r;
534 | a[j3] = x1r + x3i;
535 | a[j3 + 1] = x1i + x3r;
536 | }
537 | } else {
538 | for (j = 0; j < l; j += 2) {
539 | j1 = j + l;
540 | x0r = a[j] - a[j1];
541 | x0i = -a[j + 1] + a[j1 + 1];
542 | a[j] += a[j1];
543 | a[j + 1] = -a[j + 1] - a[j1 + 1];
544 | a[j1] = x0r;
545 | a[j1 + 1] = x0i;
546 | }
547 | }
548 | };
549 |
550 | exports.rftfsub = function (n, aBuffer, nc, cBuffer, cOffset) {
551 | let j, k, kk;
552 | let wkr, wki, xr, xi, yr, yi;
553 |
554 | const a = new Float64Array(aBuffer);
555 | const c = new Float64Array(cBuffer).subarray(cOffset);
556 |
557 | const m = n >> 1;
558 | const ks = 2 * nc / m;
559 | kk = 0;
560 | for (j = 2; j < m; j += 2) {
561 | k = n - j;
562 | kk += ks;
563 | wkr = 0.5 - c[nc - kk];
564 | wki = c[kk];
565 | xr = a[j] - a[k];
566 | xi = a[j + 1] + a[k + 1];
567 | yr = wkr * xr - wki * xi;
568 | yi = wkr * xi + wki * xr;
569 | a[j] -= yr;
570 | a[j + 1] -= yi;
571 | a[k] += yr;
572 | a[k + 1] -= yi;
573 | }
574 | };
575 |
576 | exports.rftbsub = function (n, aBuffer, nc, cBuffer, cOffset) {
577 | let j, k, kk;
578 | let wkr, wki, xr, xi, yr, yi;
579 |
580 | const a = new Float64Array(aBuffer);
581 | const c = new Float64Array(cBuffer).subarray(cOffset);
582 |
583 | a[1] = -a[1];
584 | const m = n >> 1;
585 | const ks = 2 * nc / m;
586 | kk = 0;
587 | for (j = 2; j < m; j += 2) {
588 | k = n - j;
589 | kk += ks;
590 | wkr = 0.5 - c[nc - kk];
591 | wki = c[kk];
592 | xr = a[j] - a[k];
593 | xi = a[j + 1] + a[k + 1];
594 | yr = wkr * xr + wki * xi;
595 | yi = wkr * xi - wki * xr;
596 | a[j] -= yr;
597 | a[j + 1] = yi - a[j + 1];
598 | a[k] += yr;
599 | a[k + 1] = yi - a[k + 1];
600 | }
601 | a[m + 1] = -a[m + 1];
602 | };
603 |
--------------------------------------------------------------------------------
/spec/correctness-huge-spec.js:
--------------------------------------------------------------------------------
1 | const util = require('./TestUtils.js');
2 |
3 | // THis file is separated off as it can make some editors laggy.
4 | // Tip on generating data for a filer like this using Octave / Matlab
5 | //
6 | // >> nfft = 4096;
7 | // >> y = fft(1:nfft);
8 | // >> re = real(y); re = re(1:(1+nfft/2));
9 | // >> im = imag(y); im = im(1:(1+nfft/2));
10 | // >> reStr = sprintf ('%.15g,', re);
11 | // >> imStr = sprintf ('%.15g,', im);
12 | //
13 | // Then simply copy the string values and pase.
14 |
15 | describe('FFT algorithm should work with huge sizes', () => {
16 | it('should work for real size 4096', () => {
17 | const re = new Float64Array([8390656, -2048, -2048, -2048.00000000001, -2048, -2048.00000000001, -2048.00000000001, -2047.99999999999, -2048, -2048.00000000001, -2048.00000000002, -2047.99999999998, -2048.00000000001, -2048.00000000001, -2047.99999999999, -2047.99999999998, -2048.00000000001, -2048.00000000002, -2048.00000000002, -2048, -2048.00000000001, -2047.99999999999, -2047.99999999998, -2047.99999999999, -2048, -2048, -2048, -2048.00000000001, -2047.99999999998, -2047.99999999999, -2047.99999999998, -2047.99999999996, -2048, -2048.00000000005, -2048.00000000001, -2047.99999999999, -2048.00000000001, -2047.99999999999, -2048, -2048.00000000001, -2048.00000000001, -2047.99999999999, -2047.99999999999, -2048.00000000001, -2047.99999999999, -2048, -2048, -2048.00000000002, -2048, -2047.99999999999, -2047.99999999999, -2048, -2048, -2048, -2048.00000000001, -2047.99999999998, -2047.99999999999, -2048.00000000001, -2048, -2047.99999999998, -2047.99999999998, -2047.99999999999, -2047.99999999995, -2048.00000000007, -2048, -2047.99999999993, -2048.00000000004, -2048.00000000001, -2048.00000000002, -2048.00000000001, -2048, -2047.99999999999, -2048.00000000001, -2048.00000000001, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2047.99999999999, -2048, -2048, -2048.00000000001, -2047.99999999999, -2048, -2048, -2047.99999999999, -2047.99999999999, -2048, -2048, -2048, -2048, -2048, -2047.99999999998, -2048, -2048.00000000002, -2048.00000000001, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048.00000000001, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048.00000000001, -2048, -2048, -2048, -2048, -2048.00000000002, -2048.00000000005, -2048, -2047.99999999995, -2047.99999999998, -2048, -2048.00000000001, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2047.99999999999, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2047.99999999999, -2047.99999999999, -2048, -2048.00000000001, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048.00000000001, -2048, -2048, -2048, -2048.00000000001, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2047.99999999999, -2048, -2047.99999999998, -2048.00000000002, -2048, -2047.99999999998, -2048.00000000001, -2048, -2048.00000000001, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2047.99999999999, -2048, -2048.00000000001, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2047.99999999999, -2048, -2048, -2048, -2047.99999999999, -2048, -2047.99999999999, -2047.99999999998, -2047.99999999996, -2048, -2048.00000000004, -2048.00000000003, -2048.00000000001, -2047.99999999999, -2048.00000000001, -2048, -2048, -2048, -2048.00000000001, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2047.99999999999, -2048.00000000001, -2048, -2047.99999999999, -2048.00000000001, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2047.99999999999, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2047.99999999999, -2048, -2048, -2048, -2048, -2048.00000000002, -2048, -2047.99999999998, -2048, -2048, -2048, -2047.99999999999, -2048.00000000001, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2047.99999999999, -2048.00000000001, -2048, -2047.99999999999, -2048.00000000001, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2047.99999999999, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048.00000000001, -2048, -2048, -2048, -2048, -2048, -2047.99999999999, -2048, -2048.00000000001, -2047.99999999999, -2048, -2048.00000000001, -2048.00000000002, -2048, -2048, -2048, -2047.99999999998, -2047.99999999999, -2048, -2048.00000000001, -2047.99999999999, -2048.00000000001, -2048.00000000001, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048.00000000001, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048.00000000001, -2048, -2047.99999999999, -2048.00000000001, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2047.99999999999, -2047.99999999999, -2047.99999999998, -2047.99999999999, -2048, -2048, -2048.00000000002, -2048.00000000001, -2048.00000000001, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048.00000000001, -2048, -2047.99999999999, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2047.99999999999, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2047.99999999999, -2048, -2048.00000000001, -2048, -2048, -2047.99999999999, -2048.00000000001, -2048.00000000002, -2048, -2047.99999999998, -2048, -2048.00000000002, -2048, -2047.99999999998, -2047.99999999999, -2048, -2048, -2048, -2047.99999999999, -2047.99999999999, -2048, -2048, -2048, -2048, -2048.00000000001, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2047.99999999999, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2047.99999999999, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2047.99999999998, -2048.00000000002, -2048, -2047.99999999998, -2048.00000000002, -2048, -2048, -2048.00000000001, -2048, -2047.99999999999, -2048.00000000001, -2048, -2047.99999999999, -2048, -2048, -2048.00000000001, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2047.99999999999, -2048, -2048.00000000001, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2047.99999999999, -2048.00000000001, -2047.99999999999, -2048, -2047.99999999999, -2048.00000000001, -2048.00000000001, -2048, -2048, -2048, -2047.99999999999, -2048, -2048, -2048.00000000003, -2048, -2048, -2048, -2048.00000000023, -2048, -2047.99999999977, -2048, -2048, -2048, -2047.99999999997, -2048, -2048, -2048.00000000001, -2048, -2048, -2048, -2047.99999999999, -2047.99999999998, -2048.00000000001, -2048, -2048.00000000001, -2047.99999999999, -2048.00000000001, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048.00000000001, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2047.99999999999, -2048.00000000001, -2048, -2048, -2048, -2048, -2048.00000000001, -2047.99999999999, -2048, -2048.00000000001, -2048, -2047.99999999998, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2047.99999999999, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2047.99999999999, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048.00000000001, -2048, -2048, -2048, -2048.00000000001, -2048, -2047.99999999999, -2048.00000000001, -2048, -2047.99999999998, -2048, -2048.00000000001, -2048, -2047.99999999999, -2048.00000000001, -2048, -2047.99999999999, -2048.00000000001, -2048, -2048, -2047.99999999999, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048.00000000001, -2047.99999999999, -2048.00000000001, -2047.99999999999, -2048, -2047.99999999999, -2048, -2048.00000000001, -2047.99999999999, -2048.00000000001, -2047.99999999999, -2048, -2047.99999999999, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048.00000000001, -2048, -2048.00000000001, -2048, -2048, -2048, -2048, -2048, -2048, -2047.99999999999, -2047.99999999999, -2047.99999999999, -2048, -2048.00000000001, -2048.00000000002, -2048, -2048, -2048, -2047.99999999998, -2047.99999999999, -2048, -2048.00000000001, -2048.00000000001, -2048, -2048.00000000001, -2048, -2048, -2048, -2048, -2048, -2047.99999999999, -2048, -2047.99999999999, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2047.99999999999, -2048, -2048, -2048.00000000002, -2048, -2047.99999999998, -2048, -2048, -2048.00000000001, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048.00000000001, -2047.99999999999, -2047.99999999999, -2047.99999999999, -2047.99999999999, -2048, -2048.00000000003, -2047.99999999996, -2048, -2048.00000000004, -2047.99999999998, -2047.99999999999, -2048, -2048.00000000001, -2048.00000000001, -2048.00000000001, -2047.99999999999, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2047.99999999999, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2047.99999999999, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048.00000000001, -2048, -2047.99999999999, -2048.00000000001, -2048.00000000005, -2048, -2047.99999999995, -2047.99999999999, -2048.00000000001, -2048, -2047.99999999999, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048, -2048]);
18 | const im = new Float64Array([0, 2670176.33412164, 1335087.3816625, 890057.381776597, 667542.120033692, 534032.753547642, 445026.33468965, 381450.171618733, 333767.918414336, 296681.605120543, 267012.449763753, 242737.591087995, 222508.454922578, 205391.412995451, 190719.587969397, 178003.936463757, 166877.675943007, 157060.325644658, 148333.733864525, 140525.675572963, 133498.370746229, 127140.283174605, 121360.155959207, 116082.602966154, 111244.80241719, 106793.984018562, 102685.495983228, 98881.3016036899, 95348.7979877882, 92059.87919399, 88990.1867396165, 86118.5051719964, 83426.2709700266, 80897.1707363592, 78516.8102968494, 76272.4405258117, 74152.7288670677, 72147.567905634, 70247.9141649337, 68445.6517044362, 66733.4761776518, 65104.7958572485, 63553.6467994379, 62074.6198458887, 60662.7975799251, 59313.6996885648, 58023.2354512477, 56787.6622938344, 55603.549523353, 54467.7465033909, 53377.3546484385, 52329.7027130167, 51322.3249320582, 50352.9416359631, 49419.4420195374, 48519.8687906829, 47652.4044638711, 46815.359096409, 46007.1592933669, 45226.3383306496, 44471.5272657598, 43741.4469229133, 43034.9006537879, 42350.7677877248, 41687.9976959738, 41045.6044038536, 40422.6616927172, 39818.2986405455, 39231.6955560193, 38662.0802661496, 38108.724722111, 37570.9418919065, 37048.0829119764, 36539.5344729219, 36044.7164171969, 35563.0795289846, 35094.1034985572, 34637.2950452572, 34192.1861848649, 33758.3326285576, 33335.3123019477, 32922.7239738212, 32520.1859852123, 32127.3350703524, 31743.8252618368, 31369.3268730743, 31003.5255517278, 30646.1213984355, 30296.8281456193, 29955.372391654, 29621.4928860921, 29294.939862017, 28975.4744119377, 28662.8679039491, 28356.9014351578, 28057.3653196293, 27764.0586083378, 27476.78863881, 27195.3706123423, 26919.62719684, 26649.3881534874, 26384.4899855952, 26124.775608104, 25870.0940363405, 25620.300092729, 25375.2541302639, 25134.8217716327, 24898.8736629695, 24667.2852412877, 24439.9365147149, 24216.7118547149, 23997.4997995412, 23782.1928682194, 23570.6873844071, 23362.8833095239, 23158.6840845878, 22957.9964802326, 22760.7304544167, 22566.7990173666, 22376.1181033309, 22188.6064487457, 22004.1854764417, 21822.7791855461, 21644.3140467552, 21468.7189026745, 21295.9248729419, 21125.8652638694, 20958.4754823539, 20793.6929538229, 20631.4570439967, 20471.7089842617, 20314.3918004625, 20159.4502449291, 20006.8307315718, 19856.481273882, 19708.3514256885, 19562.3922245273, 19418.5561374915, 19276.7970094363, 19137.0700134187, 18999.331603262, 18863.5394681386, 18729.6524890715, 18597.6306972614, 18467.4352341499, 18339.0283131355, 18212.3731828625, 18087.4340920089, 17964.1762555009, 17842.5658220891, 17722.5698432207, 17604.1562431488, 17487.2937902218, 17371.9520692988, 17258.1014552391, 17145.7130874185, 17034.7588452257, 16925.2113244949, 16817.0438148332, 16710.2302778046, 16604.7453259303, 16500.5642024736, 16397.662761972, 16296.0174514866, 16195.6052925372, 16096.403863695, 15998.3912838031, 15901.5461958014, 15805.8477511283, 15711.2755946762, 15617.809850278, 15525.4311067037, 15434.1204041439, 15343.8592211637, 15254.6294621051, 15166.4134449225, 15079.1938894321, 14992.9539059596, 14907.6769843713, 14823.3469834724, 14739.9481207581, 14657.4649625057, 14575.8824141923, 14495.1857112274, 14415.3604099867, 14336.392379138, 14258.267791246, 14180.9731146467, 14104.4951055811, 14028.8208005785, 13953.9375090812, 13879.8328062992, 13806.4945262899, 13733.9107552519, 13662.0698250266, 13590.9603067995, 13520.5710049949, 13450.8909513555, 13381.9093992026, 13313.6158178686, 13245.9998872966, 13179.0514928014, 13112.7607199864, 13047.1178498095, 12982.1133537961, 12917.7378893902, 12853.9822954424, 12790.8375878277, 12728.2949551903, 12666.3457548106, 12604.9815085895, 12544.1938991479, 12483.9747660358, 12424.3161020489, 12365.2100496477, 12306.6488974772, 12248.6250769828, 12191.1311591203, 12134.1598511557, 12077.7039935532, 12021.7565569482, 11966.3106392021, 11911.3594625368, 11856.8963707463, 11802.9148264833, 11749.4084086177, 11696.3708096653, 11643.7958332848, 11591.6773918405, 11540.0095040285, 11488.7862925656, 11438.0019819373, 11387.6508962048, 11337.7274568679, 11288.2261807836, 11239.1416781364, 11190.4686504616, 11142.2018887179, 11094.3362714086, 11046.8667627504, 10999.7884108876, 10953.0963461507, 10906.7857793586, 10860.8520001622, 10815.2903754291, 10770.096347668, 10725.2654334908, 10680.7932221129, 10636.6753738892, 10592.9076188858, 10549.4857554856, 10506.4056490276, 10463.663230478, 10421.2544951337, 10379.1755013559, 10337.4223693329, 10295.9912798737, 10254.8784732274, 10214.0802479318, 10173.5929596885, 10133.4130202629, 10093.5368964107, 10053.9611088282, 10014.6822311269, 9975.69688883115, 9937.00175839904, 9898.59356626466, 9860.46908790232, 9822.62514691164, 9785.05861412305, 9747.76640672309, 9710.74548739912, 9673.99286350295, 9637.50558623284, 9601.28074983329, 9565.31549081244, 9529.60698717642, 9494.15245768028, 9458.94916109507, 9423.99439549077, 9389.28549753444, 9354.81984180351, 9320.59484011359, 9286.60794086051, 9252.85662837637, 9219.33842229899, 9186.05087695479, 9152.99158075434, 9120.15815560071, 9087.54825630998, 9055.15957004376, 9022.98981575344, 8991.03674363584, 8959.29813460002, 8927.77179974495, 8896.45557984783, 8865.34734486273, 8834.44499342947, 8803.74645239221, 8773.24967632789, 8742.95264708403, 8712.85337332561, 8682.94989009121, 8653.24025835771, 8623.72256461374, 8594.39492044136, 8565.25546210615, 8536.30235015511, 8507.5337690225, 8478.94792664336, 8450.54305407441, 8422.31740512234, 8394.2692559792, 8366.39690486486, 8338.69867167621, 8311.17289764308, 8283.8179449907, 8256.63219660853, 8229.61405572538, 8202.76194559056, 8176.07430916113, 8149.54960879486, 8123.18632594898, 8096.98296088459, 8070.93803237638, 8045.05007742788, 8019.31765099184, 7993.73932569579, 7968.31369157259, 7943.03935579593, 7917.9149424206, 7892.93909212751, 7868.11046197328, 7843.42772514436, 7818.88957071556, 7794.49470341294, 7770.24184338084, 7746.1297259532, 7722.15710142879, 7698.32273485054, 7674.62540578869, 7651.06390812778, 7627.63704985737, 7604.34365286646, 7581.18255274139, 7558.15259856743, 7535.25265273361, 7512.4815907411, 7489.83830101473, 7467.32168471794, 7444.9306555707, 7422.66413967073, 7400.52107531761, 7378.50041283998, 7356.60111442562, 7334.82215395445, 7313.16251683428, 7291.62119983937, 7270.19721095168, 7248.88956920477, 7227.69730453031, 7206.61945760713, 7185.65507971277, 7164.8032325775, 7144.06298824075, 7123.43342890987, 7102.91364682123, 7082.50274410357, 7062.19983264363, 7042.00403395388, 7021.91447904247, 7001.93030828524, 6982.05067129983, 6962.27472682179, 6942.60164258264, 6923.03059519, 6903.56077000947, 6884.19136104855, 6864.92157084229, 6845.75061034076, 6826.67769879843, 6807.70206366504, 6788.82294047849, 6770.03957275905, 6751.35121190568, 6732.75711709348, 6714.25655517305, 6695.8488005714, 6677.53313519413, 6659.30884832949, 6641.17523655361, 6623.13160363739, 6605.1772604546, 6587.3115248917, 6569.53372175867, 6551.84318270146, 6534.23924611564, 6516.72125706146, 6499.28856718001, 6481.94053461086, 6464.67652391073, 6447.49590597359, 6430.39805795171, 6413.38236317812, 6396.44821109005, 6379.59499715359, 6362.82212278944, 6346.12899529978, 6329.51502779614, 6312.97963912843, 6296.52225381492, 6280.14230197332, 6263.83921925279, 6247.61244676699, 6231.46143102809, 6215.38562388171, 6199.38448244281, 6183.45746903252, 6167.6040511159, 6151.82370124048, 6136.11589697579, 6120.48012085375, 6104.91586030982, 6089.42260762505, 6073.99985986898, 6058.64711884324, 6043.36389102603, 6028.1496875174, 6013.00402398521, 5997.9264206119, 5982.91640204198, 5967.97349733031, 5953.09723989102, 5938.28716744716, 5923.5428219811, 5908.86374968552, 5894.24950091517, 5879.69963013921, 5865.21369589429, 5850.79126073816, 5836.43189120403, 5822.13515775546, 5807.90063474191, 5793.7279003549, 5779.6165365847, 5765.56612917769, 5751.57626759422, 5737.64654496707, 5723.7765580605, 5709.96590722974, 5696.21419638113, 5682.52103293279, 5668.88602777568, 5655.30879523535, 5641.78895303405, 5628.32612225347, 5614.91992729783, 5601.56999585758, 5588.27595887351, 5575.03745050134, 5561.85410807675, 5548.72557208094, 5535.65148610655, 5522.63149682407, 5509.66525394865, 5496.7524102074, 5483.89262130706, 5471.08554590208, 5458.33084556311, 5445.62818474598, 5432.97723076094, 5420.37765374238, 5407.82912661891, 5395.33132508382, 5382.88392756592, 5370.48661520076, 5358.13907180216, 5345.84098383415, 5333.59204038327, 5321.39193313117, 5309.24035632757, 5297.13700676361, 5285.08158374541, 5273.0737890681, 5261.11332699009, 5249.19990420765, 5237.33322982985, 5225.51301535379, 5213.73897464011, 5202.01082388886, 5190.32828161558, 5178.69106862774, 5167.09890800147, 5155.55152505854, 5144.04864734358, 5132.59000460169, 5121.17532875624, 5109.80435388694, 5098.4768162082, 5087.19245404772, 5075.95100782541, 5064.75222003243, 5053.59583521064, 5042.48159993212, 5031.40926277915, 5020.37857432417, 5009.38928711027, 4998.44115563157, 4987.53393631417, 4976.6673874971, 4965.84126941355, 4955.05534417246, 4944.3093757401, 4933.60312992182, 4922.93637434431, 4912.30887843808, 4901.7204134198, 4891.17075227495, 4880.65966974089, 4870.18694228992, 4859.75234811255, 4849.35566710116, 4838.99668083354, 4828.67517255688, 4818.39092717173, 4808.1437312164, 4797.93337285127, 4787.75964184346, 4777.62232955156, 4767.52122891068, 4757.45613441748, 4747.42684211551, 4737.43314958066, 4727.4748559068, 4717.55176169154, 4707.66366902221, 4697.81038146193, 4687.99170403587, 4678.2074432177, 4668.45740691609, 4658.74140446148, 4649.05924659291, 4639.41074544502, 4629.7957145352, 4620.21396875092, 4610.66532433709, 4601.14959888369, 4591.66661131345, 4582.21618186965, 4572.79813210417, 4563.41228486555, 4554.0584642872, 4544.73649577581, 4535.4462059998, 4526.18742287795, 4516.95997556812, 4507.76369445613, 4498.5984111447, 4489.46395844258, 4480.36017035375, 4471.28688206674, 4462.24392994408, 4453.23115151183, 4444.24838544929, 4435.29547157875, 4426.37225085536, 4417.47856535714, 4408.6142582751, 4399.77917390338, 4390.97315762962, 4382.1960559253, 4373.44771633633, 4364.72798747359, 4356.03671900366, 4347.37376163964, 4338.73896713199, 4330.13218825961, 4321.55327882088, 4313.00209362479, 4304.47848848233, 4295.98232019776, 4287.51344656006, 4279.07172633455, 4270.65701925441, 4262.26918601246, 4253.90808825296, 4245.57358856346, 4237.26555046676, 4228.98383841299, 4220.72831777171, 4212.49885482414, 4204.29531675541, 4196.11757164698, 4187.965488469, 4179.83893707293, 4171.73778818404, 4163.66191339413, 4155.61118515428, 4147.58547676762, 4139.58466238223, 4131.60861698415, 4123.65721639034, 4115.73033724179, 4107.82785699674, 4099.94965392384, 4092.09560709549, 4084.26559638122, 4076.45950244109, 4068.67720671921, 4060.9185914373, 4053.18353958829, 4045.47193493005, 4037.78366197912, 4030.11860600449, 4022.47665302153, 4014.85768978589, 4007.26160378746, 3999.68828324449, 3992.13761709763, 3984.60949500413, 3977.10380733204, 3969.62044515451, 3962.15930024411, 3954.72026506719, 3947.30323277837, 3939.90809721499, 3932.53475289165, 3925.18309499487, 3917.85301937768, 3910.54442255435, 3903.2572016951, 3895.99125462096, 3888.74647979858, 3881.52277633516, 3874.32004397337, 3867.13818308632, 3859.97709467268, 3852.83668035172, 3845.71684235843, 3838.61748353875, 3831.53850734467, 3824.47981782974, 3817.44131964425, 3810.42291803043, 3803.4245188181, 3796.44602842001, 3789.48735382735, 3782.54840260524, 3775.62908288833, 3768.72930337641, 3761.84897333008, 3754.98800256639, 3748.1463014546, 3741.32378091198, 3734.52035239956, 3727.73592791805, 3720.97042000364, 3714.223741724, 3707.49580667419, 3700.78652897271, 3694.09582325745, 3687.42360468186, 3680.76978891097, 3674.13429211759, 3667.51703097845, 3660.91792267042, 3654.33688486676, 3647.7738357334, 3641.22869392524, 3634.7013785825, 3628.19180932709, 3621.69990625904, 3615.2255899529, 3608.76878145429, 3602.32940227633, 3595.90737439618, 3589.50262025165, 3583.11506273779, 3576.74462520347, 3570.39123144809, 3564.05480571826, 3557.73527270446, 3551.43255753785, 3545.14658578702, 3538.8772834548, 3532.62457697505, 3526.38839320957, 3520.16865944496, 3513.96530338952, 3507.77825317021, 3501.60743732961, 3495.45278482289, 3489.31422501488, 3483.19168767704, 3477.0851029846, 3470.99440151361, 3464.91951423806, 3458.86037252707, 3452.81690814198, 3446.78905323363, 3440.7767403395, 3434.77990238102, 3428.79847266078, 3422.83238485983, 3416.88157303502, 3410.94597161631, 3405.0255154041, 3399.1201395667, 3393.22977963759, 3387.354371513, 3381.49385144922, 3375.64815606015, 3369.81722231476, 3364.0009875346, 3358.19938939133, 3352.41236590426, 3346.63985543796, 3340.88179669979, 3335.13812873757, 3329.40879093717, 3323.69372302019, 3317.99286504163, 3312.30615738753, 3306.63354077275, 3300.97495623866, 3295.33034515089, 3289.69964919711, 3284.08281038478, 3278.47977103899, 3272.89047380028, 3267.31486162244, 3261.7528777704, 3256.20446581811, 3250.66956964637, 3245.14813344084, 3239.64010168987, 3234.14541918251, 3228.66403100641, 3223.19588254584, 3217.74091947968, 3212.29908777941, 3206.87033370712, 3201.45460381359, 3196.05184493634, 3190.66200419767, 3185.28502900277, 3179.92086703783, 3174.56946626813, 3169.23077493621, 3163.90474156, 3158.59131493095, 3153.29044411229, 3148.00207843713, 3142.72616750674, 3137.46266118871, 3132.21150961524, 3126.97266318135, 3121.74607254317, 3116.53168861617, 3111.32946257352, 3106.13934584434, 3100.96129011204, 3095.79524731263, 3090.64116963311, 3085.49900950978, 3080.36871962653, 3075.2502529135, 3070.14356254523, 3065.04860193892, 3059.96532475334, 3054.89368488695, 3049.83363647614, 3044.78513389411, 3039.7481317492, 3034.72258488314, 3029.70844836984, 3024.70567751374, 3019.71422784837, 3014.73405513484, 3009.76511536047, 3004.80736473718, 2999.86075970022, 2994.92525690664, 2990.00081323387, 2985.08738577839, 2980.18493185425, 2975.29340899173, 2970.41277493594, 2965.54298764551, 2960.68400529116, 2955.83578625438, 2950.99828912615, 2946.17147270555, 2941.35529599849, 2936.54971821635, 2931.75469877477, 2926.97019729229, 2922.19617358912, 2917.43258768586, 2912.67939980225, 2907.9365703559, 2903.2040599611, 2898.48182942757, 2893.76983975921, 2889.06805215293, 2884.37642799747, 2879.69492887214, 2875.02351654571, 2870.36215297516, 2865.7108003046, 2861.06942086407, 2856.43797716837, 2851.81643191597, 2847.20474798784, 2842.60288844635, 2838.01081653416, 2833.42849567309, 2828.85588946303, 2824.29296168087, 2819.73967627941, 2815.19599738626, 2810.66188930281, 2806.13731650316, 2801.62224363305, 2797.11663550884, 2792.62045711648, 2788.13367361047, 2783.65625031281, 2779.18815271205, 2774.72934646224, 2770.27979738195, 2765.83947145326, 2761.4083348208, 2756.98635379077, 2752.57349482992, 2748.16972456469, 2743.77500978015, 2739.38931741911, 2735.01261458115, 2730.64486852172, 2726.28604665116, 2721.93611653383, 2717.59504588715, 2713.26280258073, 2708.93935463541, 2704.62467022246, 2700.31871766257, 2696.02146542508, 2691.73288212701, 2687.45293653226, 2683.18159755069, 2678.91883423731, 2674.66461579138, 2670.41891155559, 2666.18169101523, 2661.95292379732, 2657.73257966981, 2653.52062854075, 2649.31704045746, 2645.12178560573, 2640.93483430902, 2636.75615702764, 2632.58572435797, 2628.42350703166, 2624.26947591487, 2620.12360200743, 2615.98585644217, 2611.85621048404, 2607.73463552944, 2603.62110310538, 2599.5155848688, 2595.41805260579, 2591.32847823083, 2587.24683378611, 2583.17309144073, 2579.10722349001, 2575.04920235479, 2570.99900058066, 2566.95659083729, 2562.92194591769, 2558.89503873757, 2554.87584233454, 2550.86432986754, 2546.86047461601, 2542.86424997938, 2538.87562947622, 2534.89458674367, 2530.92109553675, 2526.95512972768, 2522.99666330524, 2519.04567037407, 2515.1021251541, 2511.1660019798, 2507.23727529965, 2503.31591967533, 2499.4019097814, 2495.49522040418, 2491.59582644164, 2487.70370290259, 2483.81882490575, 2479.94116767968, 2476.07070656173, 2472.20741699768, 2468.35127454106, 2464.50225485253, 2460.66033369933, 2456.82548695467, 2452.99769059715, 2449.17692071016, 2445.36315348133, 2441.55636520195, 2437.75653226639, 2433.96363117152, 2430.17763851618, 2426.39853100061, 2422.62628542589, 2418.86087869337, 2415.10228780416, 2411.35048985856, 2407.60546205552, 2403.8671816921, 2400.13562616297, 2396.41077295983, 2392.69259967091, 2388.98108398045, 2385.27620366816, 2381.57793660873, 2377.88626077127, 2374.20115421888, 2370.52259510804, 2366.85056168821, 2363.18503230126, 2359.52598538098, 2355.87339945261, 2352.22725313234, 2348.58752512683, 2344.95419423268, 2341.32723933604, 2337.70663941202, 2334.09237352431, 2330.48442082465, 2326.88276055238, 2323.28737203399, 2319.69823468261, 2316.1153279976, 2312.53863156407, 2308.96812505242, 2305.4037882179, 2301.84560090016, 2298.29354302278, 2294.74759459289, 2291.20773570064, 2287.67394651884, 2284.14620730248, 2280.62449838831, 2277.10880019443, 2273.59909321983, 2270.09535804398, 2266.59757532643, 2263.10572580635, 2259.61979030216, 2256.13974971106, 2252.66558500867, 2249.19727724862, 2245.73480756209, 2242.27815715746, 2238.8273073199, 2235.38223941097, 2231.94293486818, 2228.50937520468, 2225.0815420088, 2221.65941694368, 2218.24298174692, 2214.83221823012, 2211.42710827858, 2208.02763385087, 2204.63377697846, 2201.24551976538, 2197.86284438779, 2194.48573309365, 2191.11416820235, 2187.74813210434, 2184.38760726075, 2181.03257620306, 2177.68302153271, 2174.33892592077, 2171.00027210757, 2167.66704290236, 2164.33922118292, 2161.01678989528, 2157.69973205331, 2154.38803073844, 2151.08166909923, 2147.78063035113, 2144.48489777607, 2141.19445472215, 2137.90928460331, 2134.62937089899, 2131.35469715381, 2128.08524697723, 2124.82100404324, 2121.56195209001, 2118.30807491961, 2115.05935639764, 2111.81578045295, 2108.57733107731, 2105.3439923251, 2102.115748313, 2098.89258321967, 2095.67448128542, 2092.46142681197, 2089.25340416209, 2086.05039775931, 2082.85239208759, 2079.65937169111, 2076.47132117388, 2073.28822519941, 2070.11006849068, 2066.93683582941, 2063.76851205615, 2060.60508206981, 2057.44653082744, 2054.29284334382, 2051.1440046915, 2048, 2044.860814456, 2041.72643330287, 2038.59684184025, 2035.47202542418, 2032.35196946637, 2029.23665943422, 2026.12608085041, 2023.02021929275, 2019.9190603937, 2016.82258984044, 2013.73079337425, 2010.64365679048, 2007.56116593819, 2004.48330671995, 2001.41006509148, 1998.3414270615, 1995.27737869146, 1992.21790609519, 1989.16299543876, 1986.11263294016, 1983.06680486912, 1980.02549754675, 1976.9886973454, 1973.95639068835, 1970.92856404961, 1967.90520395363, 1964.8862969751, 1961.87182973868, 1958.86178891878, 1955.85616123932, 1952.85493347349, 1949.85809244349, 1946.86562502037, 1943.87751812372, 1940.89375872145, 1937.91433382962, 1934.93923051213, 1931.96843588059, 1929.00193709397, 1926.0397213585, 1923.08177592736, 1920.1280881005, 1917.1786452244, 1914.23343469187, 1911.29244394181, 1908.35566045902, 1905.42307177395, 1902.49466546251, 1899.57042914586, 1896.65035049016, 1893.73441720641, 1890.82261705023, 1887.9149378216, 1885.01136736472, 1882.11189356777, 1879.2165043627, 1876.32518772504, 1873.4379316737, 1870.55472427075, 1867.67555362124, 1864.80040787297, 1861.92927521634, 1859.06214388411, 1856.19900215121, 1853.33983833458, 1850.4846407929, 1847.63339792651, 1844.7860981771, 1841.9427300276, 1839.10328200195, 1836.26774266494, 1833.43610062198, 1830.60834451896, 1827.78446304205, 1824.96444491748, 1822.1482789114, 1819.33595382969, 1816.52745851777, 1813.72278186039, 1810.92191278152, 1808.1248402441, 1805.3315532499, 1802.54204083935, 1799.75629209134, 1796.97429612304, 1794.19604208976, 1791.42151918475, 1788.65071663903, 1785.88362372124, 1783.12022973743, 1780.36052403094, 1777.60449598217, 1774.85213500849, 1772.10343056399, 1769.35837213939, 1766.6169492618, 1763.87915149464, 1761.14496843741, 1758.41438972554, 1755.68740503025, 1752.96400405839, 1750.24417655224, 1747.5279122894, 1744.81520108261, 1742.10603277959, 1739.40039726287, 1736.69828444968, 1733.99968429176, 1731.3045867752, 1728.6129819203, 1725.92485978143, 1723.24021044686, 1720.55902403861, 1717.88129071231, 1715.20700065706, 1712.53614409523, 1709.86871128238, 1707.20469250708, 1704.54407809075, 1701.88685838755, 1699.23302378421, 1696.58256469988, 1693.93547158603, 1691.29173492626, 1688.65134523615, 1686.01429306319, 1683.38056898663, 1680.7501636171, 1678.12306759692, 1675.49927159972, 1672.87876633006, 1670.26154252375, 1667.64759094744, 1665.0369023985, 1662.42946770499, 1659.82527772545, 1657.22432334876, 1654.62659549406, 1652.03208511057, 1649.44078317748, 1646.85268070382, 1644.26776872834, 1641.68603831935, 1639.10748057461, 1636.53208662122, 1633.95984761546, 1631.39075474269, 1628.82479921722, 1626.26197228214, 1623.70226520929, 1621.14566929904, 1618.59217588021, 1616.04177630996, 1613.49446197365, 1610.9502242847, 1608.40905468453, 1605.87094464235, 1603.33588565513, 1600.80386924743, 1598.27488697128, 1595.74893040609, 1593.22599115852, 1590.70606086235, 1588.18913117839, 1585.67519379434, 1583.16424042468, 1580.65626281058, 1578.15125271975, 1575.64920194635, 1573.15010231088, 1570.65394566005, 1568.16072386668, 1565.67042882959, 1563.18305247349, 1560.69858674887, 1558.21702363187, 1555.73835512422, 1553.26257325307, 1550.78967007094, 1548.31963765556, 1545.85246810983, 1543.38815356163, 1540.92668616378, 1538.46805809393, 1536.01226155441, 1533.55928877217, 1531.10913199867, 1528.66178350975, 1526.21723560556, 1523.77548061043, 1521.33651087281, 1518.90031876513, 1516.4668966837, 1514.03623704863, 1511.60833230373, 1509.18317491639, 1506.76075737752, 1504.3410722014, 1501.92411192562, 1499.50986911098, 1497.09833634136, 1494.6895062237, 1492.2833713878, 1489.87992448631, 1487.4791581946, 1485.08106521066, 1482.68563825503, 1480.29287007069, 1477.90275342297, 1475.51528109944, 1473.13044590986, 1470.74824068606, 1468.36865828184, 1465.9916915729, 1463.61733345674, 1461.24557685258, 1458.87641470126, 1456.50983996514, 1454.14584562805, 1451.78442469515, 1449.4255701929, 1447.06927516891, 1444.7155326919, 1442.36433585161, 1440.01567775869, 1437.66955154462, 1435.32595036165, 1432.9848673827, 1430.64629580124, 1428.31022883127, 1425.9766597072, 1423.64558168376, 1421.31698803594, 1418.9908720589, 1416.66722706786, 1414.34604639809, 1412.02732340472, 1409.71105146278, 1407.39722396701, 1405.08583433189, 1402.77687599141, 1400.47034239918, 1398.16622702819, 1395.86452337082, 1393.56522493871, 1391.26832526274, 1388.97381789288, 1386.6816963982, 1384.39195436668, 1382.10458540529, 1379.81958313974, 1377.53694121453, 1375.25665329281, 1372.97871305635, 1370.70311420542, 1368.42985045872, 1366.15891555339, 1363.89030324483, 1361.62400730666, 1359.36002153065, 1357.09833972668, 1354.83895572259, 1352.58186336421, 1350.32705651518, 1348.07452905701, 1345.82427488886, 1343.57628792757, 1341.33056210755, 1339.08709138076, 1336.84586971654, 1334.60689110166, 1332.37014954015, 1330.13563905331, 1327.90335367958, 1325.6732874745, 1323.44543451065, 1321.21978887758, 1318.99634468171, 1316.77509604631, 1314.5560371114, 1312.33916203369, 1310.12446498655, 1307.91194015987, 1305.70158176007, 1303.49338400999, 1301.28734114885, 1299.08344743215, 1296.88169713166, 1294.6820845353, 1292.48460394711, 1290.28924968719, 1288.09601609161, 1285.90489751236, 1283.71588831731, 1281.52898289011, 1279.34417563015, 1277.1614609525, 1274.98083328783, 1272.80228708237, 1270.62581679785, 1268.45141691141, 1266.27908191558, 1264.10880631818, 1261.94058464229, 1259.77441142617, 1257.61028122324, 1255.44818860196, 1253.28812814581, 1251.13009445323, 1248.97408213757, 1246.820085827, 1244.66810016446, 1242.51811980764, 1240.37013942889, 1238.22415371515, 1236.08015736794, 1233.93814510324, 1231.79811165151, 1229.66005175757, 1227.52396018058, 1225.38983169396, 1223.25766108534, 1221.12744315654, 1218.99917272346, 1216.87284461609, 1214.74845367837, 1212.62599476822, 1210.50546275743, 1208.38685253165, 1206.27015899029, 1204.15537704651, 1202.04250162713, 1199.93152767261, 1197.82245013697, 1195.71526398778, 1193.60996420603, 1191.50654578617, 1189.40500373599, 1187.30533307662, 1185.20752884241, 1183.11158608096, 1181.01749985303, 1178.92526523247, 1176.8348773062, 1174.74633117415, 1172.65962194922, 1170.57474475721, 1168.49169473679, 1166.41046703944, 1164.3310568294, 1162.25345928362, 1160.17766959174, 1158.10368295601, 1156.03149459122, 1153.96109972472, 1151.89249359631, 1149.82567145825, 1147.76062857514, 1145.69736022394, 1143.63586169387, 1141.57612828643, 1139.51815531527, 1137.4619381062, 1135.40747199716, 1133.35475233809, 1131.30377449098, 1129.25453382977, 1127.20702574032, 1125.16124562035, 1123.11718887943, 1121.07485093888, 1119.0342272318, 1116.99531320296, 1114.95810430877, 1112.92259601726, 1110.88878380801, 1108.85666317215, 1106.82622961224, 1104.7974786423, 1102.77040578771, 1100.74500658525, 1098.72127658296, 1096.69921134005, 1094.67880642722, 1092.66005742608, 1090.64295992935, 1088.62750954112, 1086.6137018763, 1084.60153256085, 1082.59099723173, 1080.58209153681, 1078.57481113483, 1076.56915169541, 1074.56510889892, 1072.56267843655, 1070.56185601016, 1068.56263733233, 1066.56501812625, 1064.56899412574, 1062.57456107515, 1060.58171472938, 1058.5904508538, 1056.60076522423, 1054.61265362688, 1052.62611185834, 1050.64113572551, 1048.65772104561, 1046.67586364608, 1044.69555936457, 1042.71680404892, 1040.7395935571, 1038.76392375716, 1036.78979052725, 1034.8171897555, 1032.84611734004, 1030.87656918896, 1028.90854122023, 1026.94202936172, 1024.97702955114, 1023.01353773597, 1021.05154987349, 1019.09106193067, 1017.13206988419, 1015.1745697204, 1013.21855743525, 1011.26402903426, 1009.31098053252, 1007.35940795464, 1005.40930733467, 1003.46067471614, 1001.51350615196, 999.567797704423, 997.623545445158, 995.680745455089, 993.739393824415, 991.799486652566, 989.861020048171, 987.923990129021, 985.988393022041, 984.054224863251, 982.121481797726, 980.190159979589, 978.260255571946, 976.331764746862, 974.404683685345, 972.479008577288, 970.554735621446, 968.631861025423, 966.710381005603, 964.790291787125, 962.871589603896, 960.954270698494, 959.038331322182, 957.123767734844, 955.210576204984, 953.298753009666, 951.388294434507, 949.479196773623, 947.571456329615, 945.665069413525, 943.760032344812, 941.856341451322, 939.953993069259, 938.052983543138, 936.153309225772, 934.254966478231, 932.357951669823, 930.462261178057, 928.567891388604, 926.674838695274, 924.783099499996, 922.89267021278, 921.003547251669, 919.115727042747, 917.229206020073, 915.343980625685, 913.460047309535, 911.577402529489, 909.696042751279, 907.815964448494, 905.937164102515, 904.05963820254, 902.183383245509, 900.308395736089, 898.43467218665, 896.562209117248, 894.691003055561, 892.8210505369, 890.952348104164, 889.0848923078, 887.218679705801, 885.353706863656, 883.489970354329, 881.627466758255, 879.766192663258, 877.906144664577, 876.04731936481, 874.189713373916, 872.333323309141, 870.478145795022, 868.624177463368, 866.771414953225, 864.919854910789, 863.069493989545, 861.220328850037, 859.37235615994, 857.525572594077, 855.679974834322, 853.83555956961, 851.992323495831, 850.150263316077, 848.309375740098, 846.469657484813, 844.631105274051, 842.79371583832, 840.957485915313, 839.122412249359, 837.288491591659, 835.455720700214, 833.62409633981, 831.793615281908, 829.964274304722, 828.13607019321, 826.308999738924, 824.483059740095, 822.658247001574, 820.834558334805, 819.011990557771, 817.190540495059, 815.370204977741, 813.550980843391, 811.732864936057, 809.915854106241, 808.099945210877, 806.285135113287, 804.471420683182, 802.658798796626, 800.847266336013, 799.036820190052, 797.227457253725, 795.419174428288, 793.611968621232, 791.805836746253, 790.000775723254, 788.196782478303, 786.393853943618, 784.59198705753, 782.791178764475, 780.991426014981, 779.192725765612, 777.395074978985, 775.598470623712, 773.802909674409, 772.008389111644, 770.21490592194, 768.422457097743, 766.63103963739, 764.840650545106, 763.05128683097, 761.262945510898, 759.475623606616, 757.689318145646, 755.904026161273, 754.119744692541, 752.336470784213, 750.554201486765, 748.772933856354, 746.992664954799, 745.213391849561, 743.435111613734, 741.657821325999, 739.881518070622, 738.106198937428, 736.331861021782, 734.558501424556, 732.786117252146, 731.014705616393, 729.2442636346, 727.474788429529, 725.70627712933, 723.938726867563, 722.172134783155, 720.406498020393, 718.641813728891, 716.878079063587, 715.11529118471, 713.353447257762, 711.592544453501, 709.832579947918, 708.073550922221, 706.31545456282, 704.558288061288, 702.802048614371, 701.046733423932, 699.292339696976, 697.538864645588, 695.786305486942, 694.034659443268, 692.283923741842, 690.534095614956, 688.785172299912, 687.037151038989, 685.290029079441, 683.543803673459, 681.798472078166, 680.054031555599, 678.310479372678, 676.567812801195, 674.826029117806, 673.085125603998, 671.345099546063, 669.605948235104, 667.867668967005, 666.130259042405, 664.393715766689, 662.658036449973, 660.923218407077, 659.189258957506, 657.456155425443, 655.72390513973, 653.992505433829, 652.261953645841, 650.532247118447, 648.803383198931, 647.075359239132, 645.348172595433, 643.621820628754, 641.896300704531, 640.171610192691, 638.447746467645, 636.724706908243, 635.002488897827, 633.281089824108, 631.560507079254, 629.840738059816, 628.121780166654, 626.403630805105, 624.686287384779, 622.969747319609, 621.254008027837, 619.539066932017, 617.824921458981, 616.111569039789, 614.39900710975, 612.687233108408, 610.976244479568, 609.266038671124, 607.556613135202, 605.8479653281, 604.140092710219, 602.432992746135, 600.726662904491, 599.021100658054, 597.316303483653, 595.612268862195, 593.908994278617, 592.206477221899, 590.504715185023, 588.803705664988, 587.103446162764, 585.403934183287, 583.705167235453, 582.00714283208, 580.309858489924, 578.613311729639, 576.91750007576, 575.222421056704, 573.528072204751, 571.83445105601, 570.141555150431, 568.449382031765, 566.757929247569, 565.067194349177, 563.377174891696, 561.687868433972, 559.999272538604, 558.311384771893, 556.624202703861, 554.93772390822, 553.25194596235, 551.566866447305, 549.882482947773, 548.198793052081, 546.515794352176, 544.833484443599, 543.151860925486, 541.470921400541, 539.790663475033, 538.111084758768, 536.432182865085, 534.75395541084, 533.076400016388, 531.399514305569, 529.723295905694, 528.047742447539, 526.372851565314, 524.698620896665, 523.025048082645, 521.352130767717, 519.679866599725, 518.008253229889, 516.337288312788, 514.666969506333, 512.997294471793, 511.328260873728, 509.659866380003, 507.992108661789, 506.324985393519, 504.658494252892, 502.992632920847, 501.32739908157, 499.662790422456, 497.998804634112, 496.335439410338, 494.672692448112, 493.010561447576, 491.349044112031, 489.688138147913, 488.027841264781, 486.368151175312, 484.709065595276, 483.050582243535, 481.392698842021, 479.735413115715, 478.078722792665, 476.422625603934, 474.767119283607, 473.112201568787, 471.457870199554, 469.804122918981, 468.150957473103, 466.498371610911, 464.846363084335, 463.19492964824, 461.544069060394, 459.893779081479, 458.244057475067, 456.594902007601, 454.94631044839, 453.298280569596, 451.650810146222, 450.003896956096, 448.357538779858, 446.711733400952, 445.066478605603, 443.421772182823, 441.777611924383, 440.133995624802, 438.490921081344, 436.848386093992, 435.206388465453, 433.564926001121, 431.923996509084, 430.283597800126, 428.643727687665, 427.00438398779, 425.365564519231, 423.727267103331, 422.089489564071, 420.452229728024, 418.815485424346, 417.179254484792, 415.543534743659, 413.908324037813, 412.273620206685, 410.639421092179, 409.005724538751, 407.372528393539, 405.739830505872, 404.10762872757, 402.475920913218, 400.844704919695, 399.213978606292, 397.583739834798, 395.95398646941, 394.324716376714, 392.695927425727, 391.067617487852, 389.439784436857, 387.8124261489, 386.185540502473, 384.559125378426, 382.93317865993, 381.307698232491, 379.682681983913, 378.058127804292, 376.434033586038, 374.810397223799, 373.187216614522, 371.564489657383, 369.942214253816, 368.320388307463, 366.699009724212, 365.078076412137, 363.457586281519, 361.83753724482, 360.217927216676, 358.598754113887, 356.980015855408, 355.361710362328, 353.74383555787, 352.126389367376, 350.509369718294, 348.892774540158, 347.276601764609, 345.660849325346, 344.045515158139, 342.430597200805, 340.81609339321, 339.20200167724, 337.58831999681, 335.975046297844, 334.36217852826, 332.749714637966, 331.137652578842, 329.525990304746, 327.914725771477, 326.303856936787, 324.693381760356, 323.083298203797, 321.473604230627, 319.864297806263, 318.255376898025, 316.6468394751, 315.038683508555, 313.430906971312, 311.823507838144, 310.216484085659, 308.609833692295, 307.003554638316, 305.39764490577, 303.792102478536, 302.186925342251, 300.582111484327, 298.977658893969, 297.373565562113, 295.769829481442, 294.166448646386, 292.563421053086, 290.960744699401, 289.358417584897, 287.756437710836, 286.154803080148, 284.553511697454, 282.952561569025, 281.351950702792, 279.751677108324, 278.151738796825, 276.552133781121, 274.952860075644, 273.353915696438, 271.75529866113, 270.157006988939, 268.559038700635, 266.961391818574, 265.364064366657, 263.767054370313, 262.170359856515, 260.573978853758, 258.977909392044, 257.382149502879, 255.786697219257, 254.191550575658, 252.59670760804, 251.002166353811, 249.407924851839, 247.81398114243, 246.220333267328, 244.626979269693, 243.033917194102, 241.44114508654, 239.848660994376, 238.256462966374, 236.664549052651, 235.07291730472, 233.481565775424, 231.890492518949, 230.299695590839, 228.709173047944, 227.118922948428, 225.528943351779, 223.93923231877, 222.349787911452, 220.76060819318, 219.171691228546, 217.583035083416, 215.994637824903, 214.406497521354, 212.818612242373, 211.230980058737, 209.643599042454, 208.05646726676, 206.469582806046, 204.882943735893, 203.296548133094, 201.710394075471, 200.124479642171, 198.538802913472, 196.953361970632, 195.368154896169, 193.783179773669, 192.198434687818, 190.613917724446, 189.029626970431, 187.445560513721, 185.861716443359, 184.278092849438, 182.694687823103, 181.111499456538, 179.528525842966, 177.945765076613, 176.36321525274, 174.780874467604, 173.198740818453, 171.616812403528, 170.03508732204, 168.453563674162, 166.872239561044, 165.291113084766, 163.710182348346, 162.129445455751, 160.548900511853, 158.968545622448, 157.388378894214, 155.808398434743, 154.228602352508, 152.648988756849, 151.069555757976, 149.490301466955, 147.911223995718, 146.332321456994, 144.753591964381, 143.175033632283, 141.596644575915, 140.018422911297, 138.440366755238, 136.862474225335, 135.284743439969, 133.707172518265, 132.129759580122, 130.552502746194, 128.975400137848, 127.398449877206, 125.821650087104, 124.244998891082, 122.668494413399, 121.092134778992, 119.515918113494, 117.939842543206, 116.363906195107, 114.788107196831, 113.21244367665, 111.636913763492, 110.061515586915, 108.486247277086, 106.911106964799, 105.336092781449, 103.761202859034, 102.186435330114, 100.611788327871, 99.0372599860129, 97.4628484388231, 95.8885518211537, 94.3143682683731, 92.7402959164101, 91.1663329016883, 89.5924773611696, 88.0187274323143, 86.4450812530959, 84.8715369619458, 83.2980926978125, 81.7247466000917, 80.1514968086522, 78.5783414638063, 77.0052787063469, 75.4323066774414, 73.8594235187484, 72.2866273723084, 70.7139163805805, 69.1412886864273, 67.5687424331118, 65.996275764257, 64.4238868238936, 62.8515737564012, 61.2793347064944, 59.7071678192733, 58.1350712401909, 56.5630431149621, 54.9910815897019, 53.4191848107803, 51.8473509249088, 50.2755780790831, 48.703864420575, 47.132208096984, 45.5606072560913, 43.989060046013, 42.4175646150979, 40.8461191119422, 39.2747216853604, 37.7033704843998, 36.1320636583478, 34.5607993566664, 32.9895757290287, 31.4183909253334, 29.8472430956026, 28.2761303900916, 26.7050509591354, 25.1340029533312, 23.5629845233925, 21.9919938201201, 20.421028994504, 18.8500881975633, 17.2791695806081, 15.7082712948904, 14.1373914917931, 12.5665283227863, 10.995679939515, 9.42484449356562, 7.85402013669955, 6.28320502053248, 4.71239729691297, 3.14159511774778, 1.57079663476907, 0]);
19 |
20 | expect(util.TestCorrectnessReal(re, im)).toEqual({
21 | reDiffs: 0,
22 | imDiffs: 0,
23 | reverseDiffs: 0
24 | });
25 | });
26 | });
27 |
--------------------------------------------------------------------------------