Permalink
Browse files

bug fixes, cleanup

  • Loading branch information...
Ben Crowell
Ben Crowell committed Mar 27, 2009
1 parent 7b79216 commit 071fd571d514a79421d768f7ad3f739d8ce63bca
Showing with 225 additions and 142 deletions.
  1. +6 −0 Complex.js
  2. +34 −20 LeviCivita.js
  3. +130 −0 Num.js
  4. +25 −78 Parser.js
  5. +29 −44 Rational.js
  6. +1 −0 index.html
View
@@ -70,6 +70,12 @@ com.lightandmatter.Complex =
c.ceil = function() {return com.lightandmatter.Complex(Math.ceil(c.x),Math.ceil(c.y));};
c.toString = function() {
+ if (c.y==0) {return c.x.toString()}
+ if (c.x==0) {
+ if (c.y==1) {return 'i'}
+ if (c.y== -1) {return '-i'}
+ return c.y.toString()+' i';
+ }
return c.x + ' + ' + c.y + ' i';
};
View
@@ -12,17 +12,18 @@ if (!com.lightandmatter) {com.lightandmatter = {};}
com.lightandmatter.LeviCivita =
- function (front,leading,series) {
+ function (front,leading,series) { // series arg is optional
var c = {};
// form is front*d^leading*(sum a_q*d^q), where all q's are >0
c.f = front; // can be real or complex
c.l = leading; // can be Rational or an integer represented in floating point
+ if (arguments.length<3) {series = [[0,1]];}
c.s = series; // array of pairs of the form [q,a_q]; q's can be Rational or integer, and a_q's can be real or complex; first pair must be [0,1]; must be sorted
// 0 is represented with front=0 and s=[[0,1]]
c.mytype = 'l';
- c.n = 6; // number of terms to keep in the series
c.rr = com.lightandmatter.Rational(1,1); // just need one handy to get access to class methods
+ c.nn = com.lightandmatter.Num; // ...similar
c.clone = function () {
var x = com.lightandmatter.LeviCivita(c.f,c.l,[]);
@@ -41,11 +42,14 @@ com.lightandmatter.LeviCivita =
for (var i in c.s) {
var q = c.s[i][0];
var a = c.s[i][1];
- var power = c.rr.add_r(q,c.l);
- var s = '';
- s = s + (c.f*a);
- var p0 = c.rr.eq_r(power,0);
- var p1 = c.rr.eq_r(power,1);
+ var power = c.nn.binop('+',q,c.l);
+ var coeff = c.nn.binop('*',c.f,a);
+ var s = coeff.toString();
+ if (c.nn.num_type(coeff)!='r' && s.length>1) {
+ s = '('+s+')';
+ }
+ var p0 = c.nn.binop('=',power,0);
+ var p1 = c.nn.binop('=',power,1);
if (s=='1' && !p0) {s='';}
if (s=='-1' && !p0) {s='-';}
if (!p0) {s = s + 'd';}
@@ -56,15 +60,19 @@ com.lightandmatter.LeviCivita =
};
c.neg = function() {
var z = c.clone();
- z.f = -z.f;
+ z.f = c.nn.binop('-',0,z.f);
return z;
};
c.add = function (b) {
if (c.f===0) {return b;} // Otherwise we divide by zero below.
var z = c.clone();
+ var h = c.nn.binop('-',b.l,c.l);
+ var ff = c.nn.binop('/',b.f,c.f);
for (var i in b.s) {
- var q = b.s[i][0]+b.l-c.l;
- var a = b.s[i][1]*b.f/c.f;
+ var q = c.nn.binop('+',b.s[i][0],h);
+ //c.debug("multiplying "+b.s[i][1]+" * "+ff);
+ var a = c.nn.binop('*',b.s[i][1],ff);
+ //c.debug("...result = "+a);
z.s.push([q,a]);
}
z.tidy();
@@ -74,24 +82,26 @@ com.lightandmatter.LeviCivita =
return c.add(b.neg()); // add() handles tidying
}
c.mul = function (b) {
- var z = com.lightandmatter.LeviCivita(b.f*c.f,c.rr.add_r(b.l,c.l),[]);;
+ var z = com.lightandmatter.LeviCivita(c.nn.binop('*',b.f,c.f),c.nn.binop('+',b.l,c.l));;
+ z.s = [];
for (var i in b.s) {
for (var j in c.s) {
- var q = c.rr.add_r(b.s[i][0],c.s[j][0]);
- var a = c.rr.mul_r(b.s[i][1],c.s[j][1]);
+ var q = c.nn.binop('+',b.s[i][0],c.s[j][0]);
+ var a = c.nn.binop('*',b.s[i][1],c.s[j][1]);
z.s.push([q,a]);
}
}
z.tidy();
return z;
};
c.tidy = function() {
- c.s.sort(function(a,b) {return c.rr.cmp_r(a[0],b[0])});
+ c.s.sort(function(a,b) {return c.nn.binop('cmp',a[0],b[0])});
var ss = [];
var last_q = null;
for (var i=0; i<c.s.length; i++) {
- if (c.rr.cmp_r(c.s[i][0],last_q)===0) {
- ss[ss.length-1][1] += c.s[i][1];
+ if (c.nn.binop('cmp',c.s[i][0],last_q)===0) {
+ ss[ss.length-1][1] = c.nn.binop('+',ss[ss.length-1][1],c.s[i][1]);
+ //c.debug('a = '+ss[ss.length-1][1]);
}
else {
ss.push(c.s[i]);
@@ -100,16 +110,18 @@ com.lightandmatter.LeviCivita =
}
c.s = ss;
for (var i=0; i<c.s.length; i++) {
- if (c.rr.cmp_r(c.s[i][1],0)===0) {
+ if (c.nn.binop('cmp',c.s[i][1],0)===0) {
c.s.splice(i,1);
}
}
if (c.s.length===0) {c = c.zero()}
- c.s.splice(c.n); // truncate to c.n terms
+ c.s.splice(com.lightandmatter.LeviCivita.n); // truncate to n terms
var k = c.s[0][1];
- c.f = c.f*k;
+ c.f = c.nn.binop('*',c.f,k);
+ //c.debug('new front = '+c.f);
for (var i=0; i<c.s.length; i++) {
- c.s[i][1] = c.s[i][1]/k;
+ c.s[i][1] = c.nn.binop('/',c.s[i][1],k);
+ //c.debug('new a = '+c.s[i][1].tidy());
}
};
@@ -120,3 +132,5 @@ com.lightandmatter.LeviCivita =
return c;
};
+
+com.lightandmatter.LeviCivita.n = 6; // number of terms to keep in the series
View
130 Num.js
@@ -0,0 +1,130 @@
+// Num.js
+// (c) 2007 B. Crowell, GPL 2 license
+//
+// This file provides a module, com.lightandmatter.Num.
+//
+
+var com;
+if (!com) {com = {};}
+if (!com.lightandmatter) {com.lightandmatter = {};}
+
+
+com.lightandmatter.Num = {};
+
+com.lightandmatter.Num.describe_type = function(t) {
+ if (t=='q') {return 'rational';}
+ if (t=='r') {return 'real';}
+ if (t=='c') {return 'complex';}
+ if (t=='l') {return 'Levi-Civita';}
+ return t;
+ };
+
+com.lightandmatter.Num.promote = function(x,y) {
+ var nn = com.lightandmatter.Num;
+ var tx = nn.num_type(x);
+ var ty = nn.num_type(y);
+ if (tx==ty) {return [tx,x,y];}
+ if (nn.height(tx)<nn.height(ty)) {
+ var v = nn.promote(y,x);
+ var z = v[1];
+ v[1] = v[2];
+ v[2] = z;
+ return v;
+ }
+ // From here on, we're guaranteed that x is the higher type, y needs promotion.
+ var tt = tx+ty;
+
+ // ---complex and (real|rational) ---
+ if (tt=='cr' || tt=='cq') {
+ if (ty=='q') {y=y.toNumber()}
+ return ['c',x,com.lightandmatter.Complex(y,0)];
+ }
+ // real & rational --- test for whether r is integer
+ // ---real and rational---
+ if (tt=='rq') {
+ if (x==Math.floor(x)) {
+ // In the following, we have to defeat simplification into real.
+ var u = com.lightandmatter.Rational(1,42); // 1/42 is something that won't get returned as a real by the constructor.
+ u.x = x; u.y=1;
+ return ['q',u,y];
+ } // demote real to rational, because it's actually an integer
+ return ['r',x,y.toNumber()];
+ }
+ // ---LC and (real | complex | rational) ---
+ if (tt=='lr' || tt=='lc' || tt=='lq') {
+ if (ty=='q') {y=y.toNumber()}
+ return ['l',x,com.lightandmatter.LeviCivita(y,0,[[0,1]])];
+ }
+ return [null,null,null,["unable to do type promotion, types="+tx+','+ty]];
+ };
+
+com.lightandmatter.Num.binop = function(op,a,b) {
+ var nn = com.lightandmatter.Num;
+ var prom = nn.promote(a,b);
+ var t = prom[0];
+ a = prom[1];
+ b = prom[2];
+ if (t!='r' && t!='c' && t!='l' && t!='q') {
+ return null;
+ }
+ if (op=='=') {
+ if (t=='r') {return a==b;} else {return a.eq(b);}
+ }
+ if (op=='cmp') {
+ if (t=='r') {return a-b;} else {return a.cmp(b);}
+ }
+ if (op=='<') {
+ if (t=='r') {return a<b;}
+ }
+ if (op=='>') {
+ if (t=='r') {return a>b;}
+ }
+ if (op=='+') {
+ if (t=='r') {return a+b;} else {return a.add(b);}
+ }
+ if (op=='-') {
+ if (t=='r') {return a-b;} else {return a.sub(b);}
+ }
+ if (op=='*') {
+ if (t=='r') {return a*b;} else {return a.mul(b);}
+ }
+ if (op=='/') {
+ if (t=='r') {
+ if (b===0.0) {return NaN;}
+ if (a===Math.floor(a) && b===Math.floor(b)) {return com.lightandmatter.Rational(a,b);}
+ return a/b;
+ }
+ else {
+ return a.div(b);
+ }
+ }
+ if (op=='^') {
+ if (t=='r') {
+ if (a===0 && b===0) {return NaN;}
+ if (a===0 && b<0) {return NaN;}
+ return Math.pow(a,b);
+ }
+ else {
+ return a.pow(b);
+ }
+ }
+ return null;
+ };
+
+com.lightandmatter.Num.num_type = function(x) {
+ if (x===null) {return null;}
+ if (typeof(x)=='number') {return 'r';} // real
+ if (x.mytype == 'q') {return 'q';} // rational
+ if (x.mytype == 'c') {return 'c';} // complex
+ if (x.mytype == 'l') {return 'l';} // Levi-Civita
+ return null;
+ };
+
+// typically we promote to the "higher" type:
+com.lightandmatter.Num.height = function (t) {
+ return {'q':1,'r':2,'c':3,'l':4}[t];
+ };
+
+com.lightandmatter.Num.debug = function(s) {
+ document.getElementById("debug").innerHTML=document.getElementById("debug").innerHTML+' '+s+' ';
+ };
Oops, something went wrong.

0 comments on commit 071fd57

Please sign in to comment.