node.js -- 數學計算

JavaScript

簡介

歷史

開發工具

基本語法

運算式

分枝

迴圈

函數

陣列

物件導向

原型

封裝

繼承

多型

this

控制流程

進階功能

Eval 函數

Closure

JSONP

小書籤

字串

正規表達式

除錯方法

伺服端

播 midi

cookie

套件

ccc函式庫

2D 繪圖

3D 繪圖

影像處理

訊號處理

語音處理

數學計算

tex 數學式

格式轉換

桌面應用

自然語言

地理資訊

平台

Node.js

jQuery

Google

numeric.js

Titanium

引擎

語法

作品

翻譯精靈

繪圖精靈

DotWiki

流程

前端工程師

後端工程師

css

訊息

相關網站

參考文獻

最新修改

簡體版

English

我創建的 MathNode.js 專案

  1. 專案壓縮檔:mathnode_v3.zip
  2. GitHub: https://github.com/ccckmit/mathnode

純 JavaScript 的科學計算函式庫

  1. 矩陣函式庫 — http://www.numericjs.com/ (超讚!)
  2. 統計函式庫 — http://www.jstat.org/ (超讚!)

numericjs

其中的 WorkShop 其實是用 flot 包裝後的函式庫,如下所示。

<script>
"use strict";
var _indexOf;
if(typeof Array.indexOf === "undefined") {
    _indexOf = function(t,obj){
   for(var i=0; i<t.length; i++){
    if(t[i]==obj){
     return i;
    }
   }
   return -1;
  }
} else _indexOf = function(t,obj) { return t.indexOf(obj); }

var _retarded = false;
if (/MSIE (\d+\.\d+);/.test(navigator.userAgent)){ _retarded = true; }

if(_retarded) {
    _queue = [];
    _onmessage = function(ev) { _queue.push(ev); }
    _loaded = 0;
    window.Worker = function(f) {
        var worker = this;
        worker.queue = [];
        worker.onmessage = function(ev) {};
        worker.postMessage = function(ev) { _onmessage({data: ev}); };
        var scr = document.createElement('script');
        scr.src = f;
        scr.type = 'text/javascript';
        scr.onreadystatechange = function () {
            var k;
            if (scr.readyState == 'loaded' || scr.readyState == 'complete') {
                for(k=0;k<_queue.length;k++) { _onmessage(_queue[k]); }
            }
        }
        document.getElementsByTagName('head')[0].appendChild(scr);
        workerPostMessage = function(ev) { worker.onmessage({data: ev}); }
    }
    importScripts = function(z) {
        var scr = document.createElement('script');
        scr.src = z;
        scr.type = 'text/javascript';
        document.getElementsByTagName('head')[0].appendChild(scr);
    };
}
var workshop = (function () {

function resize(input) {
    if(input.scrollHeight > input.clientHeight) {
        input.style.height = (input.scrollHeight+10)+"px";
    }
}

function elementPos(e){
    var x = 0, y = 0, dx = e.offsetWidth, dy = e.offsetHeight;
    while(e !== null){
        x += e.offsetLeft;
        y += e.offsetTop;
        e = e.offsetParent;
      }
      return {x:x, y:y, dx:dx, dy:dy};
}

function checkpos(e) {
    var foo = elementPos(e);
    var y = window.pageYOffset, dy = window.innerHeight;
    if(foo.y < y+10 || foo.y+foo.dy > y+dy-10) {
        window.scrollTo(window.pageXOffset,Math.max(0,Math.round(foo.y-0.5*dy)));
    }    
}

function myfocus(e) {
    checkpos(e);
    e.focus();
}

var savedata;
var cache = [];
var count = 0;
var clear = [];
var divcount = 0;
var divorder = [0];

var w = new Worker('myworker.js');
var plotcount = 0;

function plotit(plotid,x) {
    var k;
    try {
        if(typeof x.s === "object") $('#'+plotid).css(x.s);
        $.plot($("#"+plotid), x.p, x.o);
    } catch(e) {
        var _foo = e.toString();
           if(typeof e.stack !== "undefined" && typeof e.stack.toString !== "undefined") {
               _foo += "\n\n"+e.stack.toString();
           }
           _foo = _foo.replace(/&/g,'&amp;').replace(/>/g,'&gt;').replace(/</g,'&lt;').replace(/"/g,'&quot;');
           $('#'+plotid).after(_foo);
        $('#'+plotid).remove();
    }
}

var savereq = false;
function saveit() {
    if(!savereq) {
        savereq = true;
        setTimeout(function () {
            savereq = false;
            localStorage.savedata = JSON.stringify(savedata);
        },1000);
    }
}

function outputChanged(k,o) {
    var i = _indexOf(divorder,k);
    savedata.outputs[i].push(o);
    saveit();
}

w.onmessage = function(ev) {
    var x = JSON.parse(ev.data);
    var y = $('#out_'+x.k.toString())[0];
    if(clear[x.k]) { y.innerHTML = ''; savedata.outputs[_indexOf(divorder,x.k)] = []; }
    if(typeof x.p !== "undefined") {
        var plotid = "plot_"+plotcount.toString();
        plotcount++;
        y.innerHTML += '<div class="plot" id="'+plotid+'"></div>';
        (function () { 
            setTimeout(function () { 
                plotit(plotid,x); 
                setTimeout(function () { 
                    outputChanged(x.k,x); 
                },0); 
            },0); 
        }());
        clear[x.k] = false;
        return;
    } 
    else { 
        y.innerHTML += x.o;
        (function () {
            setTimeout(function() { 
                outputChanged(x.k,x.o); },0) 
            }());
        clear[x.k] = false;
    }
}
function mkdiv(i) {
    divcount++;
    var foo = _indexOf(divorder,i);
    divorder.splice(foo+1,0,divcount);
    savedata.inputs.splice(foo+1,0,'');
    savedata.outputs.splice(foo+1,0,[]);
    $('#output_'+i.toString()).after(
    '<div class="inner" id = "input_'+divcount.toString()+'">'+
        '<div class="caret">IN></div>'+
        '<div class="input"><textarea rows=1 id = "text_'+divcount.toString()+'" class="input" onkeydown="workshop.mykeydown(event,'+divcount.toString()+');"></textarea></div>'+
        '<div class="button"><a href="#" onclick="workshop.rmdiv('+divcount.toString()+')" class="button">&#x2716;</a></div>'+
    '</div>'+
    '<div class="inner" id = "output_'+divcount.toString()+'">'+
        '<div class="out">OUT></div>'+
        '<div id = "out_'+divcount.toString()+'" class="output"></div>'+
        '<div class="button2"><a href="#" onclick="workshop.mkdiv('+divcount.toString()+');" class="button">&#x21A9;</a></div>'+
    '</div>'
    );
}
function rmdiv(i) {
    var foo = _indexOf(divorder,i);
    divorder.splice(foo,1);
    $('#input_'+i.toString()).remove();
    $('#output_'+i.toString()).remove();
    savedata.inputs.splice(foo,1);
    savedata.outputs.splice(foo,1);
}

function go(k) {
    var input = $('#text_'+k.toString())[0];
    var n = _indexOf(divorder,k);
    var foo = divorder[n+1];
    if(typeof foo === "number") {
           myfocus($('#text_'+foo.toString())[0]);
    } else {
        mkdiv(k);
        foo = divorder[n+1];
    }
    input.className = "runned";
    cache[k] = input.value;
    myfocus($('#text_'+foo.toString())[0]);
    clear[k] = true;
    $('#out_'+k.toString())[0].innerHTML = "<img src=\"resources/wait16.gif\">";
    var runit = function() { w.postMessage(JSON.stringify({k:k,n:n,e:input.value})); }
    setTimeout(runit,0);
}

function inputChanged(k){
    var i = _indexOf(divorder,k);
    var input = $('#text_'+k.toString())[0];
    if(input.value === cache[k]) input.className = "runned";
    else { input.className = "input"; cache[k] = null; }
    savedata.inputs[i] = input.value;
    saveit();
}

var _foo;
var rc = 0;
function restore2(foo) {
    if(foo) _foo = foo;
    rc++;
    if(rc<2) return;
    foo = _foo;
    savedata = { inputs: [], outputs: [], scripts: foo.scripts };
    var baz = 'Version: <tt>'+foo.scripts[0]+'</tt>';
    if(_indexOf(foo.scripts,workshop.updateVersion)<0) {
        baz = baz + ' (Update to <tt><a href="javascript: workshop.update();">'+workshop.updateVersion+'</a></tt>)';
    }
    $('#divupdate')[0].innerHTML = baz;
    if(foo.inputs.length === 0) { mkdiv(0); return; }
    var input,output,i,j,f0;
    for(i=1;i<foo.inputs.length;i++) {
        mkdiv(i-1);
        input = $('#text_'+i.toString())[0];
        input.value = foo.inputs[i];
        f0 = (function(in0) { return function() { resize(in0); }; }(input));
        setTimeout(f0,0);
        output = $('#out_'+i.toString())[0];
        if(typeof foo.outputs[i] === "undefined") { continue; }
        for(j=0;j<foo.outputs[i].length;j++) {
            if(typeof foo.outputs[i][j] === "string") {
                output.innerHTML += foo.outputs[i][j];
            } else {
                (function(i,j) {
                    var plotid = "plot_"+plotcount.toString();
                    plotcount++;
                    output.innerHTML += '<div class="plot" id="'+plotid+'"></div>';
                    setTimeout(function () { 
                        plotit(plotid,{k:i, o:foo.outputs[i][j].o, p:foo.outputs[i][j].p});
                    },0);
                }(i,j));
            }
        }
    }
    savedata = foo;
    workshop.savedata = savedata;
}

function restore(savedata) {
    w.postMessage(JSON.stringify({imports:savedata.scripts}));
    restore2(savedata);
}

function preload(savedata) {
    var k;
    var client;

    for(k=0;k<savedata.scripts.length;k++) {
        client = new XMLHttpRequest();
        client.open("GET", savedata.scripts[k]);
        client.send();
    }
}

function mykeydown(e,i) {
    var input = $('#text_'+i.toString())[0];
    checkpos(input);
    resize(input);
    setTimeout(function () { resize(input); },0);
    var e = window.event?window.event:e;
    if(e.keyCode === 13 && e.shiftKey === false) {
        setTimeout(function () { inputChanged(i); go(i); },0);
        if(window.event) e.returnValue = false;
        else e.preventDefault();
    } else {
        setTimeout(function () { inputChanged(i); },0)
    };
}
function reset() {
    localStorage.clear();
    window.location.replace('workshop.php');
}
function update() {
    savedata.scripts = [workshop.updateVersion];
    localStorage.savedata = JSON.stringify(savedata);
    window.location.replace('workshop.php');
}

function submit() {
    var f = document.myform;
    var foo = JSON.stringify(savedata);
    var digest = Crypto.SHA256(foo, { asBytes: true });
    var s = document.myform.savedata;
    s.value = foo;
    digest = Crypto.util.bytesToHex(digest);
    f.action = "workshop.php?link="+digest;
    f.submit();
}

return {
        print:print,
        mkdiv:mkdiv,
        rmdiv:rmdiv,
        mykeydown:mykeydown,
        w:w,
        savedata:savedata,
        restore:restore,
        restore2:restore2,
        reset:reset,
        resize:resize,
        submit:submit,
        update:update,
        preload:preload
        }
}());
</script>

<script>
workshop._restore = ((typeof localStorage.savedata === "string")?
                    (JSON.parse(localStorage.savedata)):
                    {inputs: [], outputs: [], 
                     scripts: ["lib/numeric-1.1.8.js"] });
workshop.version = "1.1.8";
workshop.updateVersion = "lib/numeric-1.1.8.js";
workshop.preload(workshop._restore);
</script>

<script>
workshop.restore(workshop._restore);
</script>

jStat

D:\ccc101\JavaScript\jstat-jstat-6d68253>make insall
make: *** No rule to make target `insall'.  Stop.

D:\ccc101\JavaScript\jstat-jstat-6d68253>make install
'Downloading necessary libraries for build'
npm http GET https://registry.npmjs.org/uglify-js/1.2.3
npm http GET https://registry.npmjs.org/vows
npm http 200 https://registry.npmjs.org/uglify-js/1.2.3
npm http GET https://registry.npmjs.org/uglify-js/-/uglify-js-1.2.3.tgz
npm http 200 https://registry.npmjs.org/vows
npm http GET https://registry.npmjs.org/vows/-/vows-0.6.3.tgz
npm http 200 https://registry.npmjs.org/uglify-js/-/uglify-js-1.2.3.tgz
npm http 200 https://registry.npmjs.org/vows/-/vows-0.6.3.tgz
npm http GET https://registry.npmjs.org/eyes
npm http 200 https://registry.npmjs.org/eyes
npm http GET https://registry.npmjs.org/eyes/-/eyes-0.1.7.tgz
npm http 200 https://registry.npmjs.org/eyes/-/eyes-0.1.7.tgz
uglify-js@1.2.3 node_modules\uglify-js

vows@0.6.3 node_modules\vows
└── eyes@0.1.7

D:\ccc101\JavaScript\jstat-jstat-6d68253>make test
'Cleaning up build files'
'Building jStat'
命令語法不正確。
make: *** [jstat.js] Error 1

D:\ccc101\JavaScript\jstat-jstat-6d68253>

而且專案的 README 中也寫到:

*NOTE:* The code in this repository does not currently match that found on www.jstat.org. We are in the process of merging two similar projects and will update the website once the merge is complete.

因此還得等到專案成熟,所以我想可以先用 numericjs 作矩陣運算,jstat 僅作統計之用。

這個專案的 doctool.js 顯然是用 node.js 作的,而且用了 markd (Markdown) 的文件描述語法。

var fs = require("fs"),
    path = require("path"),
    markdown = require("./lib/markdown"),
    argv = process.argv,
    argc = argv.length,
    template = fs.readFileSync(argv[2], "utf8");

純 JavaScript 的科學計算函式庫

  1. http://www.numericjs.com/ (超讚!)
  2. http://sylvester.jcoglan.com/docs.html (好!)
  3. http://code.google.com/p/webgl-mjs/

numericjs

  • http://www.numericjs.com/
    • Linear algebra
    • Complex numbers
    • Splines
    • ODE solver
    • Unconstrained optimization
    • PDE and sparse linear algebra

sylvester (矩陣運算)

var M1 = $M([
  [1,7,3],
  [9,4,0],
  [2,7,1]
]);

var M2 = $M([
  [6,2,8],
  [9,1,3],
  [0,7,6]
]);

var M = M1.x(M2);

// M is the matrix
//   69 30 47
//   90 22 84
//   75 18 43

node-gsl — 統計運算

範例:

var gsl = require('gsl'),
    seed = 50,
    deviation = 0.5;

console.log( gsl.random.gaussian(deviation) );
console.log( gsl.random.gaussian(seed, deviation) );

var iterator = new gsl.Random(seed);
console.log( iterator.gaussian(deviation) );
console.log( iterator.gaussian(deviation) );
  1. gsl.Random([seed])
    • Construct a new iterator, seel below for available random methods.
  2. gsl.random.get([seed])
  3. gsl.Random.get()
    • Returns a random integer. The minimum and maximum values depend on the algorithm used, but all integers in the range [min,max] are equally likely. The values of min and max can determined using the auxiliary functions random.min() and random.max().
  4. gsl.random.min()
  5. gsl.Random.min()
    • Returns the smallest value that random.get() can return.
  6. gsl.random.max()
  7. gsl.Random.max()
    • Returns the largest value that random.get() can return.
  8. gsl.random.uniform([seed])
  9. gsl.Random.uniform()
    • Returns a double precision floating point number uniformly distributed in the range [0,1). The range includes 0.0 but excludes 1.0.
  10. gsl.random.gaussian([seed], deviation)
  11. gsl.Random.gaussian(deviation)
    • Returns a Gaussian random float with mean zero given a standart deviation as a float.
  12. gsl.random.gaussianZiggurat([seed], deviation)
  13. gsl.Random.gaussianZiggurat(deviation)
    • Same as random.gaussian but using the alternative Marsaglia-Tsang ziggurat method.
  14. gsl.random.gaussianRatioMethod([seed], deviation)
  15. gsl.Random.gaussianRatioMethod(deviation)
    • Same as random.gaussian but using the alternative Kinderman-Monahan-Leva ratio method.
  16. gsl.random.poisson([seed], mean)
  17. gsl.Random.poisson(mean)
    • Returns a random integer from the Poisson distribution given a provided mean as a float.

參考文獻

  1. https://github.com/wdavidw/node-gsl
  2. http://nodejsmodules.org/tags/mathematics
    • gsl — GNU Scientific Library for NodeJS.
    • science — Scientific and statistical computing in JavaScript.
    • lmj-maths — a library of mathematics routines
    • gtest — g-test algorithm to compute statistical significance
    • gamma — the gamma function (Γ) Try it out
    • chi-squared — characteristic functions for chi-squared distributions

Facebook

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 3.0 License