├── .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 [![npm version](https://badge.fury.io/js/ooura.svg)](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 | [![Circle Status](https://circleci.com/gh/audioplastic/ooura/tree/master.png?circle-token=63d6565456f01dec4f3c77d14bef5a1ce4e7143a)](https://circleci.com/gh/audioplastic/ooura) | [![Circle Status](https://circleci.com/gh/audioplastic/ooura/tree/develop.png?circle-token=63d6565456f01dec4f3c77d14bef5a1ce4e7143a)](https://circleci.com/gh/audioplastic/ooura) | 9 | | Appveyor | [![Build status](https://ci.appveyor.com/api/projects/status/2f31v1etdumb9jkp/branch/master?svg=true)](https://ci.appveyor.com/project/audioplastic/ooura/branch/master)| [![Build status](https://ci.appveyor.com/api/projects/status/2f31v1etdumb9jkp/branch/develop?svg=true)](https://ci.appveyor.com/project/audioplastic/ooura/branch/develop) | 10 | | Travis | [![Build Status](https://travis-ci.org/audioplastic/ooura.svg?branch=master)](https://travis-ci.org/audioplastic/ooura) | [![Build Status](https://travis-ci.org/audioplastic/ooura.svg?branch=develop)](https://travis-ci.org/audioplastic/ooura) | 11 | | Coveralls | [![Coverage Status](https://coveralls.io/repos/github/audioplastic/ooura/badge.svg?branch=master)](https://coveralls.io/github/audioplastic/ooura?branch=master) | [![Coverage Status](https://coveralls.io/repos/github/audioplastic/ooura/badge.svg?branch=develop)](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 | ![latest performance](https://github.com/audioplastic/fft-js-benchmark/raw/master/img/3-9-2017.png) 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 [![XO code style](https://img.shields.io/badge/try_me-RunKit-orange.svg)](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 [![XO code style](https://img.shields.io/badge/try_me-RunKit-orange.svg)](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) [![XO code style](https://img.shields.io/badge/try_me-RunKit-orange.svg)](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 [![XO code style](https://img.shields.io/badge/code_style-XO-5ed9c7.svg)](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 | --------------------------------------------------------------------------------