added browser test

This commit is contained in:
SheetJS 2016-10-13 13:43:49 -04:00
parent 73ee33e402
commit 75ae1499db
11 changed files with 7037 additions and 7 deletions

1
.gitignore vendored

@ -1,2 +1,3 @@
node_modules
misc/coverage.html
ctest/sauce*

@ -33,6 +33,17 @@ clean: ## Remove targets and build artifacts
test mocha: test.js $(TARGET) ## Run test suite
mocha -R spec -t 20000
.PHONY: ctest
ctest: ## Build browser test (into ctest/ subdirectory)
cp -f test.js ctest/test.js
cp -f shim.js ctest/shim.js
cp -f $(TARGET) ctest/
.PHONY: ctestserv
ctestserv: ## Start a test server on port 8000
@cd ctest && python -mSimpleHTTPServer
## Code Checking
.PHONY: lint

@ -47,14 +47,14 @@ The return value is a JS number. `NaN` signals an error in calculation.
For example:
```js
> // var BESSEL = require('bessel'); // uncomment this line if in node
> BESSEL.besselj(1.5,0) // 0.5118276712499389
> BESSEL.bessely(1.5,0) // 0.38244892476502895
> BESSEL.besseli(1.5,0) // 1.6467232021476754
> BESSEL.besselk(1.5,0) // 0.2138055693236539
// var BESSEL = require('bessel'); // uncomment this line if in node
BESSEL.besselj(1.5,0) // 0.5118276712499389
BESSEL.bessely(1.5,0) // 0.38244892476502895
BESSEL.besseli(1.5,0) // 1.6467232021476754
BESSEL.besselk(1.5,0) // 0.2138055693236539
> var Y = BESSEL.bessely
> Y(Math.PI, 5) + Y(Math.PI, 3) - (2 * 4 / Math.PI) * Y(Math.PI, 4) // 0
var Y = BESSEL.bessely
Y(Math.PI, 5) + Y(Math.PI, 3) - (2 * 4 / Math.PI) * Y(Math.PI, 4) // 0
```
## Testing
@ -85,6 +85,8 @@ granted by the MIT License are reserved by the Original Author.
## Badges
[![Build Status](https://saucelabs.com/browser-matrix/bessel.svg)](https://saucelabs.com/u/bessel)
[![Build Status](https://travis-ci.org/SheetJS/bessel.svg?branch=master)](https://travis-ci.org/SheetJS/bessel)
[![Coverage Status](http://img.shields.io/coveralls/SheetJS/bessel/master.svg)](https://coveralls.io/r/SheetJS/bessel?branch=master)

246
ctest/bessel.js Normal file

@ -0,0 +1,246 @@
/* bessel.js (C) 2013-present SheetJS -- http://sheetjs.com */
/* vim: set ts=2: */
/*exported BESSEL */
var BESSEL;
(function (factory) {
/*jshint ignore:start */
if(typeof DO_NOT_EXPORT_BESSEL === 'undefined') {
if('object' === typeof exports) {
factory(exports);
} else if ('function' === typeof define && define.amd) {
define(function () {
var module = {};
factory(module);
return module;
});
} else {
factory(BESSEL = {});
}
} else {
factory(BESSEL = {});
}
/*jshint ignore:end */
}(function(BESSEL) {
BESSEL.version = '0.3.0';
var M = Math;
function _horner(arr, v) { for(var i = 0, z = 0; i < arr.length; ++i) z = v * z + arr[i]; return z; }
function _bessel_iter(x, n, f0, f1, sign) {
if(n === 0) return f0;
if(n === 1) return f1;
var tdx = 2 / x, f2 = f1;
for(var o = 1; o < n; ++o) {
f2 = f1 * o * tdx + sign * f0;
f0 = f1; f1 = f2;
}
return f2;
}
function _bessel_wrap(bessel0, bessel1, name, nonzero, sign) {
return function bessel(x,n) {
if(nonzero) {
if(x === 0) return (nonzero == 1 ? -Infinity : Infinity);
else if(x < 0) return NaN;
}
if(n === 0) return bessel0(x);
if(n === 1) return bessel1(x);
if(n < 0) return NaN;
n|=0;
var b0 = bessel0(x), b1 = bessel1(x);
return _bessel_iter(x, n, b0, b1, sign);
};
}
var besselj = (function() {
var W = 0.636619772; // 2 / Math.PI
var b0_a1a = [57568490574.0, -13362590354.0, 651619640.7, -11214424.18, 77392.33017, -184.9052456].reverse();
var b0_a2a = [57568490411.0, 1029532985.0, 9494680.718, 59272.64853, 267.8532712, 1.0].reverse();
var b0_a1b = [1.0, -0.1098628627e-2, 0.2734510407e-4, -0.2073370639e-5, 0.2093887211e-6].reverse();
var b0_a2b = [-0.1562499995e-1, 0.1430488765e-3, -0.6911147651e-5, 0.7621095161e-6, -0.934935152e-7].reverse();
function bessel0(x) {
var a=0, a1=0, a2=0, y = x * x;
if(x < 8) {
a1 = _horner(b0_a1a, y);
a2 = _horner(b0_a2a, y);
a = a1 / a2;
} else {
var xx = x - 0.785398164;
y = 64 / y;
a1 = _horner(b0_a1b, y);
a2 = _horner(b0_a2b, y);
a = M.sqrt(W/x)*(M.cos(xx)*a1-M.sin(xx)*a2*8/x);
}
return a;
}
var b1_a1a = [72362614232.0, -7895059235.0, 242396853.1, -2972611.439, 15704.48260, -30.16036606].reverse();
var b1_a2a = [144725228442.0, 2300535178.0, 18583304.74, 99447.43394, 376.9991397, 1.0].reverse();
var b1_a1b = [1.0, 0.183105e-2, -0.3516396496e-4, 0.2457520174e-5, -0.240337019e-6].reverse();
var b1_a2b = [0.04687499995, -0.2002690873e-3, 0.8449199096e-5, -0.88228987e-6, 0.105787412e-6].reverse();
function bessel1(x) {
var a=0, a1=0, a2=0, y = x*x, xx = M.abs(x) - 2.356194491;
if(Math.abs(x)< 8) {
a1 = x*_horner(b1_a1a, y);
a2 = _horner(b1_a2a, y);
a = a1 / a2;
} else {
y = 64 / y;
a1=_horner(b1_a1b, y);
a2=_horner(b1_a2b, y);
a=M.sqrt(W/M.abs(x))*(M.cos(xx)*a1-M.sin(xx)*a2*8/M.abs(x));
if(x < 0) a = -a;
}
return a;
}
return function besselj(x, n) {
n = Math.round(n);
if(!isFinite(x)) return isNaN(x) ? x : 0;
if(n < 0) return ((n%2)?-1:1)*besselj(x, -n);
if(x < 0) return ((n%2)?-1:1)*besselj(-x, n);
if(n === 0) return bessel0(x);
if(n === 1) return bessel1(x);
if(x === 0) return 0;
var ret=0.0;
if(x > n) {
ret = _bessel_iter(x, n, bessel0(x), bessel1(x),-1);
} else {
var m=2*M.floor((n+M.floor(M.sqrt(40*n)))/2);
var jsum=false;
var bjp=0.0, sum=0.0;
var bj=1.0, bjm = 0.0;
var tox = 2 / x;
for (var j=m;j>0;j--) {
bjm=j*tox*bj-bjp;
bjp=bj;
bj=bjm;
if (M.abs(bj) > 1E10) {
bj *= 1E-10;
bjp *= 1E-10;
ret *= 1E-10;
sum *= 1E-10;
}
if (jsum) sum += bj;
jsum=!jsum;
if (j == n) ret=bjp;
}
sum=2.0*sum-bj;
ret /= sum;
}
return ret;
};
})();
var bessely = (function() {
var W = 0.636619772;
var b0_a1a = [-2957821389.0, 7062834065.0, -512359803.6, 10879881.29, -86327.92757, 228.4622733].reverse();
var b0_a2a = [40076544269.0, 745249964.8, 7189466.438, 47447.26470, 226.1030244, 1.0].reverse();
var b0_a1b = [1.0, -0.1098628627e-2, 0.2734510407e-4, -0.2073370639e-5, 0.2093887211e-6].reverse();
var b0_a2b = [-0.1562499995e-1, 0.1430488765e-3, -0.6911147651e-5, 0.7621095161e-6, -0.934945152e-7].reverse();
function bessel0(x) {
var a=0, a1=0, a2=0, y = x * x, xx = x - 0.785398164;
if(x < 8) {
a1 = _horner(b0_a1a, y);
a2 = _horner(b0_a2a, y);
a = a1/a2 + W * besselj(x,0) * M.log(x);
} else {
y = 64 / y;
a1 = _horner(b0_a1b, y);
a2 = _horner(b0_a2b, y);
a = M.sqrt(W/x)*(M.sin(xx)*a1+M.cos(xx)*a2*8/x);
}
return a;
}
var b1_a1a = [-0.4900604943e13, 0.1275274390e13, -0.5153438139e11, 0.7349264551e9, -0.4237922726e7, 0.8511937935e4].reverse();
var b1_a2a = [0.2499580570e14, 0.4244419664e12, 0.3733650367e10, 0.2245904002e8, 0.1020426050e6, 0.3549632885e3, 1].reverse();
var b1_a1b = [1.0, 0.183105e-2, -0.3516396496e-4, 0.2457520174e-5, -0.240337019e-6].reverse();
var b1_a2b = [0.04687499995, -0.2002690873e-3, 0.8449199096e-5, -0.88228987e-6, 0.105787412e-6].reverse();
function bessel1(x) {
var a=0, a1=0, a2=0, y = x*x, xx = x - 2.356194491;
if(x < 8) {
a1 = x*_horner(b1_a1a, y);
a2 = _horner(b1_a2a, y);
a = a1/a2 + W * (besselj(x,1) * M.log(x) - 1 / x);
} else {
y = 64 / y;
a1=_horner(b1_a1b, y);
a2=_horner(b1_a2b, y);
a=M.sqrt(W/x)*(M.sin(xx)*a1+M.cos(xx)*a2*8/x);
}
return a;
}
return _bessel_wrap(bessel0, bessel1, 'BESSELY', 1, -1);
})();
var besseli = (function() {
var b0_a = [1.0, 3.5156229, 3.0899424, 1.2067492, 0.2659732, 0.360768e-1, 0.45813e-2].reverse();
var b0_b = [0.39894228, 0.1328592e-1, 0.225319e-2, -0.157565e-2, 0.916281e-2, -0.2057706e-1, 0.2635537e-1, -0.1647633e-1, 0.392377e-2].reverse();
function bessel0(x) {
if(x <= 3.75) return _horner(b0_a, x*x/(3.75*3.75));
return M.exp(M.abs(x))/M.sqrt(M.abs(x))*_horner(b0_b, 3.75/M.abs(x));
}
var b1_a = [0.5, 0.87890594, 0.51498869, 0.15084934, 0.2658733e-1, 0.301532e-2, 0.32411e-3].reverse();
var b1_b = [0.39894228, -0.3988024e-1, -0.362018e-2, 0.163801e-2, -0.1031555e-1, 0.2282967e-1, -0.2895312e-1, 0.1787654e-1, -0.420059e-2].reverse();
function bessel1(x) {
if(x < 3.75) return x * _horner(b1_a, x*x/(3.75*3.75));
return (x < 0 ? -1 : 1) * M.exp(M.abs(x))/M.sqrt(M.abs(x))*_horner(b1_b, 3.75/M.abs(x));
}
return function besseli(x, n) {
n = Math.round(n);
if(n === 0) return bessel0(x);
if(n === 1) return bessel1(x);
if(n < 0) return NaN;
if(M.abs(x) === 0) return 0;
if(x == Infinity) return Infinity;
var ret = 0.0, j, tox = 2 / M.abs(x), bip = 0.0, bi=1.0, bim=0.0;
var m=2*M.round((n+M.round(M.sqrt(40*n)))/2);
for (j=m;j>0;j--) {
bim=j*tox*bi + bip;
bip=bi; bi=bim;
if (M.abs(bi) > 1E10) {
bi *= 1E-10;
bip *= 1E-10;
ret *= 1E-10;
}
if(j == n) ret = bip;
}
ret *= besseli(x, 0) / bi;
return x < 0 && (n%2) ? -ret : ret;
};
})();
var besselk = (function() {
var b0_a = [-0.57721566, 0.42278420, 0.23069756, 0.3488590e-1, 0.262698e-2, 0.10750e-3, 0.74e-5].reverse();
var b0_b = [1.25331414, -0.7832358e-1, 0.2189568e-1, -0.1062446e-1, 0.587872e-2, -0.251540e-2, 0.53208e-3].reverse();
function bessel0(x) {
if(x <= 2) return -M.log(x/2) * besseli(x,0) + _horner(b0_a, x*x/4);
return M.exp(-x) / M.sqrt(x) * _horner(b0_b, 2/x);
}
var b1_a = [1.0, 0.15443144, -0.67278579, -0.18156897, -0.1919402e-1, -0.110404e-2, -0.4686e-4].reverse();
var b1_b = [1.25331414, 0.23498619, -0.3655620e-1, 0.1504268e-1, -0.780353e-2, 0.325614e-2, -0.68245e-3].reverse();
function bessel1(x) {
if(x <= 2) return M.log(x/2) * besseli(x,1) + (1/x) * _horner(b1_a, x*x/4);
return M.exp(-x)/M.sqrt(x)*_horner(b1_b, 2/x);
}
return _bessel_wrap(bessel0, bessel1, 'BESSELK', 2, 1);
})();
BESSEL.besselj = besselj;
BESSEL.bessely = bessely;
BESSEL.besseli = besseli;
BESSEL.besselk = besselk;
}));

2
ctest/fakeassert.js Normal file

@ -0,0 +1,2 @@
var assert = {};
assert.equal = function(x,y) { if(x !== y) throw new Error(x + " !== " + y); };

23
ctest/index.html Normal file

@ -0,0 +1,23 @@
<!DOCTYPE html>
<html>
<head>
<title>Mocha</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="mocha.css" />
</head>
<body>
<div id="mocha"></div>
<script src="shim.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/json3/3.3.2/json3.min.js"></script>
<script src="bessel.js"></script>
<script src="fakeassert.js"></script>
<script src="mocha.js"></script>
<script src="sauce-client.js"></script>
<script>mocha.setup('bdd')</script>
<script src="test.js"></script>
<script>
mocha_sauce();
</script>
</body>
</html>

305
ctest/mocha.css Normal file

@ -0,0 +1,305 @@
@charset "utf-8";
body {
margin:0;
}
#mocha {
font: 20px/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif;
margin: 60px 50px;
}
#mocha ul,
#mocha li {
margin: 0;
padding: 0;
}
#mocha ul {
list-style: none;
}
#mocha h1,
#mocha h2 {
margin: 0;
}
#mocha h1 {
margin-top: 15px;
font-size: 1em;
font-weight: 200;
}
#mocha h1 a {
text-decoration: none;
color: inherit;
}
#mocha h1 a:hover {
text-decoration: underline;
}
#mocha .suite .suite h1 {
margin-top: 0;
font-size: .8em;
}
#mocha .hidden {
display: none;
}
#mocha h2 {
font-size: 12px;
font-weight: normal;
cursor: pointer;
}
#mocha .suite {
margin-left: 15px;
}
#mocha .test {
margin-left: 15px;
overflow: hidden;
}
#mocha .test.pending:hover h2::after {
content: '(pending)';
font-family: arial, sans-serif;
}
#mocha .test.pass.medium .duration {
background: #c09853;
}
#mocha .test.pass.slow .duration {
background: #b94a48;
}
#mocha .test.pass::before {
content: '✓';
font-size: 12px;
display: block;
float: left;
margin-right: 5px;
color: #00d6b2;
}
#mocha .test.pass .duration {
font-size: 9px;
margin-left: 5px;
padding: 2px 5px;
color: #fff;
-webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
-moz-box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
box-shadow: inset 0 1px 1px rgba(0,0,0,.2);
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
-ms-border-radius: 5px;
-o-border-radius: 5px;
border-radius: 5px;
}
#mocha .test.pass.fast .duration {
display: none;
}
#mocha .test.pending {
color: #0b97c4;
}
#mocha .test.pending::before {
content: '◦';
color: #0b97c4;
}
#mocha .test.fail {
color: #c00;
}
#mocha .test.fail pre {
color: black;
}
#mocha .test.fail::before {
content: '✖';
font-size: 12px;
display: block;
float: left;
margin-right: 5px;
color: #c00;
}
#mocha .test pre.error {
color: #c00;
max-height: 300px;
overflow: auto;
}
#mocha .test .html-error {
overflow: auto;
color: black;
line-height: 1.5;
display: block;
float: left;
clear: left;
font: 12px/1.5 monaco, monospace;
margin: 5px;
padding: 15px;
border: 1px solid #eee;
max-width: 85%; /*(1)*/
max-width: calc(100% - 42px); /*(2)*/
max-height: 300px;
word-wrap: break-word;
border-bottom-color: #ddd;
-webkit-border-radius: 3px;
-webkit-box-shadow: 0 1px 3px #eee;
-moz-border-radius: 3px;
-moz-box-shadow: 0 1px 3px #eee;
border-radius: 3px;
}
#mocha .test .html-error pre.error {
border: none;
-webkit-border-radius: none;
-webkit-box-shadow: none;
-moz-border-radius: none;
-moz-box-shadow: none;
padding: 0;
margin: 0;
margin-top: 18px;
max-height: none;
}
/**
* (1): approximate for browsers not supporting calc
* (2): 42 = 2*15 + 2*10 + 2*1 (padding + margin + border)
* ^^ seriously
*/
#mocha .test pre {
display: block;
float: left;
clear: left;
font: 12px/1.5 monaco, monospace;
margin: 5px;
padding: 15px;
border: 1px solid #eee;
max-width: 85%; /*(1)*/
max-width: calc(100% - 42px); /*(2)*/
word-wrap: break-word;
border-bottom-color: #ddd;
-webkit-border-radius: 3px;
-webkit-box-shadow: 0 1px 3px #eee;
-moz-border-radius: 3px;
-moz-box-shadow: 0 1px 3px #eee;
border-radius: 3px;
}
#mocha .test h2 {
position: relative;
}
#mocha .test a.replay {
position: absolute;
top: 3px;
right: 0;
text-decoration: none;
vertical-align: middle;
display: block;
width: 15px;
height: 15px;
line-height: 15px;
text-align: center;
background: #eee;
font-size: 15px;
-moz-border-radius: 15px;
border-radius: 15px;
-webkit-transition: opacity 200ms;
-moz-transition: opacity 200ms;
transition: opacity 200ms;
opacity: 0.3;
color: #888;
}
#mocha .test:hover a.replay {
opacity: 1;
}
#mocha-report.pass .test.fail {
display: none;
}
#mocha-report.fail .test.pass {
display: none;
}
#mocha-report.pending .test.pass,
#mocha-report.pending .test.fail {
display: none;
}
#mocha-report.pending .test.pass.pending {
display: block;
}
#mocha-error {
color: #c00;
font-size: 1.5em;
font-weight: 100;
letter-spacing: 1px;
}
#mocha-stats {
position: fixed;
top: 15px;
right: 10px;
font-size: 12px;
margin: 0;
color: #888;
z-index: 1;
}
#mocha-stats .progress {
float: right;
padding-top: 0;
}
#mocha-stats em {
color: black;
}
#mocha-stats a {
text-decoration: none;
color: inherit;
}
#mocha-stats a:hover {
border-bottom: 1px solid #eee;
}
#mocha-stats li {
display: inline-block;
margin: 0 5px;
list-style: none;
padding-top: 11px;
}
#mocha-stats canvas {
width: 40px;
height: 40px;
}
#mocha code .comment { color: #ddd; }
#mocha code .init { color: #2f6fad; }
#mocha code .string { color: #5890ad; }
#mocha code .keyword { color: #8a6343; }
#mocha code .number { color: #2f6fad; }
@media screen and (max-device-width: 480px) {
#mocha {
margin: 60px 0px;
}
#mocha #stats {
position: absolute;
}
}

5842
ctest/mocha.js Normal file

File diff suppressed because it is too large Load Diff

237
ctest/shim.js Normal file

@ -0,0 +1,237 @@
// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
if (!Object.keys) {
Object.keys = (function () {
var hasOwnProperty = Object.prototype.hasOwnProperty,
hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'),
dontEnums = [
'toString',
'toLocaleString',
'valueOf',
'hasOwnProperty',
'isPrototypeOf',
'propertyIsEnumerable',
'constructor'
],
dontEnumsLength = dontEnums.length;
return function (obj) {
if (typeof obj !== 'object' && typeof obj !== 'function' || obj === null) throw new TypeError('Object.keys called on non-object');
var result = [];
for (var prop in obj) {
if (hasOwnProperty.call(obj, prop)) result.push(prop);
}
if (hasDontEnumBug) {
for (var i=0; i < dontEnumsLength; i++) {
if (hasOwnProperty.call(obj, dontEnums[i])) result.push(dontEnums[i]);
}
}
return result;
};
})();
}
// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
if (!Array.prototype.filter)
{
Array.prototype.filter = function(fun /*, thisp */)
{
"use strict";
if (this == null)
throw new TypeError();
var t = Object(this);
var len = t.length >>> 0;
if (typeof fun != "function")
throw new TypeError();
var res = [];
var thisp = arguments[1];
for (var i = 0; i < len; i++)
{
if (i in t)
{
var val = t[i]; // in case fun mutates this
if (fun.call(thisp, val, i, t))
res.push(val);
}
}
return res;
};
}
// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/Trim
if (!String.prototype.trim) {
String.prototype.trim = function () {
return this.replace(/^\s+|\s+$/g, '');
};
}
// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
if (!Array.prototype.forEach)
{
Array.prototype.forEach = function(fun /*, thisArg */)
{
"use strict";
if (this === void 0 || this === null)
throw new TypeError();
var t = Object(this);
var len = t.length >>> 0;
if (typeof fun !== "function")
throw new TypeError();
var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
for (var i = 0; i < len; i++)
{
if (i in t)
fun.call(thisArg, t[i], i, t);
}
};
}
// Production steps of ECMA-262, Edition 5, 15.4.4.19
// Reference: http://es5.github.com/#x15.4.4.19
if (!Array.prototype.map) {
Array.prototype.map = function(callback, thisArg) {
var T, A, k;
if (this == null) {
throw new TypeError(" this is null or not defined");
}
// 1. Let O be the result of calling ToObject passing the |this| value as the argument.
var O = Object(this);
// 2. Let lenValue be the result of calling the Get internal method of O with the argument "length".
// 3. Let len be ToUint32(lenValue).
var len = O.length >>> 0;
// 4. If IsCallable(callback) is false, throw a TypeError exception.
// See: http://es5.github.com/#x9.11
if (typeof callback !== "function") {
throw new TypeError(callback + " is not a function");
}
// 5. If thisArg was supplied, let T be thisArg; else let T be undefined.
if (thisArg) {
T = thisArg;
}
// 6. Let A be a new array created as if by the expression new Array(len) where Array is
// the standard built-in constructor with that name and len is the value of len.
A = new Array(len);
// 7. Let k be 0
k = 0;
// 8. Repeat, while k < len
while(k < len) {
var kValue, mappedValue;
// a. Let Pk be ToString(k).
// This is implicit for LHS operands of the in operator
// b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk.
// This step can be combined with c
// c. If kPresent is true, then
if (k in O) {
// i. Let kValue be the result of calling the Get internal method of O with argument Pk.
kValue = O[ k ];
// ii. Let mappedValue be the result of calling the Call internal method of callback
// with T as the this value and argument list containing kValue, k, and O.
mappedValue = callback.call(T, kValue, k, O);
// iii. Call the DefineOwnProperty internal method of A with arguments
// Pk, Property Descriptor {Value: mappedValue, : true, Enumerable: true, Configurable: true},
// and false.
// In browsers that support Object.defineProperty, use the following:
// Object.defineProperty(A, Pk, { value: mappedValue, writable: true, enumerable: true, configurable: true });
// For best browser support, use the following:
A[ k ] = mappedValue;
}
// d. Increase k by 1.
k++;
}
// 9. return A
return A;
};
}
// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf
if (!Array.prototype.indexOf) {
Array.prototype.indexOf = function (searchElement, fromIndex) {
if ( this === undefined || this === null ) {
throw new TypeError( '"this" is null or not defined' );
}
var length = this.length >>> 0; // Hack to convert object.length to a UInt32
fromIndex = +fromIndex || 0;
if (Math.abs(fromIndex) === Infinity) {
fromIndex = 0;
}
if (fromIndex < 0) {
fromIndex += length;
if (fromIndex < 0) {
fromIndex = 0;
}
}
for (;fromIndex < length; fromIndex++) {
if (this[fromIndex] === searchElement) {
return fromIndex;
}
}
return -1;
};
}
// Based on https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray
if (! Array.isArray) {
Array.isArray = function(obj) {
return Object.prototype.toString.call(obj) === "[object Array]";
};
}
// https://github.com/ttaubert/node-arraybuffer-slice
// (c) 2013 Tim Taubert <tim@timtaubert.de>
// arraybuffer-slice may be freely distributed under the MIT license.
"use strict";
if (typeof ArrayBuffer !== 'undefined' && !ArrayBuffer.prototype.slice) {
ArrayBuffer.prototype.slice = function (begin, end) {
begin = (begin|0) || 0;
var num = this.byteLength;
end = end === (void 0) ? num : (end|0);
// Handle negative values.
if (begin < 0) begin += num;
if (end < 0) end += num;
if (num === 0 || begin >= num || begin >= end) {
return new ArrayBuffer(0);
}
var length = Math.min(num - begin, end - begin);
var target = new ArrayBuffer(length);
var targetArray = new Uint8Array(target);
targetArray.set(new Uint8Array(this, begin, length));
return target;
};
}

124
ctest/test.js Normal file

@ -0,0 +1,124 @@
/* vim: set ts=2: */
var X;
if(typeof require !== 'undefined') {
assert = require('assert');
describe('source',function(){
it('should load',function(){X=require('./');});
it('all bessel functions', function() {
assert.equal(typeof X.besseli, 'function');
assert.equal(typeof X.besselj, 'function');
assert.equal(typeof X.besselk, 'function');
assert.equal(typeof X.bessely, 'function');
});
});
} else { X = BESSEL; }
function approx(a, b, t) { return Math.abs((a - b) / (Math.abs(a) + Math.abs(b))) <= t; }
function chk(func, x, n, v, F, t) {
var V = func(x,n);
if(!approx(V, v, t) && v != V && !(isNaN(v) && isNaN(V))) throw new Error(F + "(" + x + "," + n + ") = " + V + " !~ " + v);
}
var funcs = ['besseli', 'besselj', 'besselk', 'bessely'];
var tests = {
'besseli': [
[1.5, 1, 0.981666],
[1.9, 2, 0.603272435],
[2.5, 1, 2.516716242]
],
'besselj': [
[1.5, 1, 0.557936508],
[1.9, 2, 0.329925829],
[2.5, 1, 0.497094103]
],
'besselk': [
[1.5, 1, 0.277388],
[1.9, 2, 0.296909301],
[2.5, 1, 0.073890816]
],
'bessely': [
[1.5, 1, -0.412308627],
[1.9, 2, -0.669878674],
[2.5, 1, 0.14591814]
] };
describe('correctness', function() {
funcs.forEach(function(F) { it(F, function() {
tests[F].forEach(function(t) { chk(X[F], t[0], t[1], t[2], F, 1e-6); });
});});
if(typeof require != 'undefined') {
var fs = require('fs');
it('excel', function() {
var xl = fs.readFileSync("test_files/excel.tsv", 'ascii').split("\n").map(function(l) { return l.split("\t");});
xl.forEach(function(l) { if(l.length < 6) return;
var x=Number(l[0]), n=Number(l[1]);
var i=Number(l[2]), j=Number(l[3]), k=Number(l[4]), y=Number(l[5]);
chk(X.besseli, x, n, i, 'besseli', 1e-4);
chk(X.besselj, x, n, j, 'besselj', 1e-4);
chk(X.besselk, x, n, k, 'besselk', 1e-4);
chk(X.bessely, x, n, y, 'bessely', 1e-4);
});
});
it('mma', function() {
var mma = fs.readFileSync("test_files/mma.tsv", 'ascii').split("\n").map(function(l) { return l.split("\t");});
mma.forEach(function(l) { if(l.length < 6) return;
var x=Number(l[0]), n=Number(l[1]);
var i=Number(l[2]), j=Number(l[3]), k=Number(l[4]), y=Number(l[5]);
chk(X.besseli, x, n, i, 'besseli', 1e-5);
chk(X.besselj, x, n, j, 'besselj', 1e-5);
chk(X.besselk, x, n, k, 'besselk', 1e-5);
chk(X.bessely, x, n, y, 'bessely', 1e-5);
});
});
}
});
var rand = [
0.3946086812775882, 3.946086812775882, 39.46086812775882,
0.03119419917289612, 0.3119419917289612, 3.119419917289612,
0.18311903629136062, 1.8311903629136062, 18.311903629136062,
0.5317681126599452, 5.317681126599452, 53.17681126599452,
0.37724541457032235, 3.7724541457032235, 37.724541457032235,
0.8287802926845655, 8.287802926845655, 82.87802926845655,
0.7197724866379658, 7.197724866379658, 71.97724866379658
];
describe('properties', function() {
var t = 1e-4;
it('limiting behavior', function() {
chk(X.besselj, 0, 0, 1, 'besselj', 1e-6);
chk(X.besseli, 0, 0, 1, 'besseli', 1e-6);
chk(X.besselk, 0, 0, Infinity, 'besselk', 1e-6);
chk(X.bessely, 0, 0, -Infinity, 'bessely', 1e-6);
for(var i = 1; i < 20; ++i) {
chk(X.besselj, 0, i, 0, 'besselj', 1e-6);
chk(X.besseli, 0, i, 0, 'besseli', 1e-6);
}
});
it('besselj', function() {
var F = "BESSELJ", f = X.besselj;
rand.forEach(function(r) {
for(var n = 0; n < 20; ++n) {
var pp = f( r, n), pn = f( r, -n), np = f(-r, n), nn = f(-r, -n);
if((n%2)) {
/* besselj odd if n is odd */
if(!approx(np, -pp, t)) throw new Error(F + " np[" + np + "] != -pp[" + (-pp) + "] (" + r + "," + n + ")");
if(!approx(nn, -pn, t)) throw new Error(F + " nn[" + nn + "] != -pn[" + (-pn) + "] (" + r + "," + n + ")");
/* asymmetric in n */
if(!approx(pn, -pp, t)) throw new Error(F + " pn[" + pn + "] != -pp[" + (-pp) + "] (" + r + "," + n + ")");
if(!approx(nn, -np, t)) throw new Error(F + " nn[" + nn + "] != -pn[" + (-pn) + "] (" + r + "," + n + ")");
} else {
/* besselj even if n is even */
if(!approx(np, pp, t)) throw new Error(F + " np[" + np + "] != pp[" + (pp) + "] (" + r + "," + n + ")");
if(!approx(nn, pn, t)) throw new Error(F + " nn[" + nn + "] != pn[" + (pn) + "] (" + r + "," + n + ")");
/* symmetric in n */
if(!approx(pn, pp, t)) throw new Error(F + " pn[" + pn + "] != pp[" + (pp) + "] (" + r + "," + n + ")");
if(!approx(nn, np, t)) throw new Error(F + " nn[" + nn + "] != pn[" + (pn) + "] (" + r + "," + n + ")");
}
}
});
});
});

237
shim.js Normal file

@ -0,0 +1,237 @@
// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
if (!Object.keys) {
Object.keys = (function () {
var hasOwnProperty = Object.prototype.hasOwnProperty,
hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'),
dontEnums = [
'toString',
'toLocaleString',
'valueOf',
'hasOwnProperty',
'isPrototypeOf',
'propertyIsEnumerable',
'constructor'
],
dontEnumsLength = dontEnums.length;
return function (obj) {
if (typeof obj !== 'object' && typeof obj !== 'function' || obj === null) throw new TypeError('Object.keys called on non-object');
var result = [];
for (var prop in obj) {
if (hasOwnProperty.call(obj, prop)) result.push(prop);
}
if (hasDontEnumBug) {
for (var i=0; i < dontEnumsLength; i++) {
if (hasOwnProperty.call(obj, dontEnums[i])) result.push(dontEnums[i]);
}
}
return result;
};
})();
}
// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
if (!Array.prototype.filter)
{
Array.prototype.filter = function(fun /*, thisp */)
{
"use strict";
if (this == null)
throw new TypeError();
var t = Object(this);
var len = t.length >>> 0;
if (typeof fun != "function")
throw new TypeError();
var res = [];
var thisp = arguments[1];
for (var i = 0; i < len; i++)
{
if (i in t)
{
var val = t[i]; // in case fun mutates this
if (fun.call(thisp, val, i, t))
res.push(val);
}
}
return res;
};
}
// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/Trim
if (!String.prototype.trim) {
String.prototype.trim = function () {
return this.replace(/^\s+|\s+$/g, '');
};
}
// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
if (!Array.prototype.forEach)
{
Array.prototype.forEach = function(fun /*, thisArg */)
{
"use strict";
if (this === void 0 || this === null)
throw new TypeError();
var t = Object(this);
var len = t.length >>> 0;
if (typeof fun !== "function")
throw new TypeError();
var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
for (var i = 0; i < len; i++)
{
if (i in t)
fun.call(thisArg, t[i], i, t);
}
};
}
// Production steps of ECMA-262, Edition 5, 15.4.4.19
// Reference: http://es5.github.com/#x15.4.4.19
if (!Array.prototype.map) {
Array.prototype.map = function(callback, thisArg) {
var T, A, k;
if (this == null) {
throw new TypeError(" this is null or not defined");
}
// 1. Let O be the result of calling ToObject passing the |this| value as the argument.
var O = Object(this);
// 2. Let lenValue be the result of calling the Get internal method of O with the argument "length".
// 3. Let len be ToUint32(lenValue).
var len = O.length >>> 0;
// 4. If IsCallable(callback) is false, throw a TypeError exception.
// See: http://es5.github.com/#x9.11
if (typeof callback !== "function") {
throw new TypeError(callback + " is not a function");
}
// 5. If thisArg was supplied, let T be thisArg; else let T be undefined.
if (thisArg) {
T = thisArg;
}
// 6. Let A be a new array created as if by the expression new Array(len) where Array is
// the standard built-in constructor with that name and len is the value of len.
A = new Array(len);
// 7. Let k be 0
k = 0;
// 8. Repeat, while k < len
while(k < len) {
var kValue, mappedValue;
// a. Let Pk be ToString(k).
// This is implicit for LHS operands of the in operator
// b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk.
// This step can be combined with c
// c. If kPresent is true, then
if (k in O) {
// i. Let kValue be the result of calling the Get internal method of O with argument Pk.
kValue = O[ k ];
// ii. Let mappedValue be the result of calling the Call internal method of callback
// with T as the this value and argument list containing kValue, k, and O.
mappedValue = callback.call(T, kValue, k, O);
// iii. Call the DefineOwnProperty internal method of A with arguments
// Pk, Property Descriptor {Value: mappedValue, : true, Enumerable: true, Configurable: true},
// and false.
// In browsers that support Object.defineProperty, use the following:
// Object.defineProperty(A, Pk, { value: mappedValue, writable: true, enumerable: true, configurable: true });
// For best browser support, use the following:
A[ k ] = mappedValue;
}
// d. Increase k by 1.
k++;
}
// 9. return A
return A;
};
}
// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf
if (!Array.prototype.indexOf) {
Array.prototype.indexOf = function (searchElement, fromIndex) {
if ( this === undefined || this === null ) {
throw new TypeError( '"this" is null or not defined' );
}
var length = this.length >>> 0; // Hack to convert object.length to a UInt32
fromIndex = +fromIndex || 0;
if (Math.abs(fromIndex) === Infinity) {
fromIndex = 0;
}
if (fromIndex < 0) {
fromIndex += length;
if (fromIndex < 0) {
fromIndex = 0;
}
}
for (;fromIndex < length; fromIndex++) {
if (this[fromIndex] === searchElement) {
return fromIndex;
}
}
return -1;
};
}
// Based on https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray
if (! Array.isArray) {
Array.isArray = function(obj) {
return Object.prototype.toString.call(obj) === "[object Array]";
};
}
// https://github.com/ttaubert/node-arraybuffer-slice
// (c) 2013 Tim Taubert <tim@timtaubert.de>
// arraybuffer-slice may be freely distributed under the MIT license.
"use strict";
if (typeof ArrayBuffer !== 'undefined' && !ArrayBuffer.prototype.slice) {
ArrayBuffer.prototype.slice = function (begin, end) {
begin = (begin|0) || 0;
var num = this.byteLength;
end = end === (void 0) ? num : (end|0);
// Handle negative values.
if (begin < 0) begin += num;
if (end < 0) end += num;
if (num === 0 || begin >= num || begin >= end) {
return new ArrayBuffer(0);
}
var length = Math.min(num - begin, end - begin);
var target = new ArrayBuffer(length);
var targetArray = new Uint8Array(target);
targetArray.set(new Uint8Array(this, begin, length));
return target;
};
}