Refactor math library

This commit is contained in:
James Roseborough
2012-09-10 14:21:18 +00:00
parent f8b7e1ee1c
commit 382b3b998e
5 changed files with 172 additions and 154 deletions

View File

@@ -27,6 +27,9 @@ import org.luaj.vm2.LuaDouble;
import org.luaj.vm2.LuaTable; import org.luaj.vm2.LuaTable;
import org.luaj.vm2.LuaValue; import org.luaj.vm2.LuaValue;
import org.luaj.vm2.Varargs; import org.luaj.vm2.Varargs;
import org.luaj.vm2.lib.jme.JmePlatform;
import org.luaj.vm2.lib.jse.JseMathLib;
import org.luaj.vm2.lib.jse.JsePlatform;
/** /**
* Subclass of {@link LibFunction} which implements the lua standard {@code math} * Subclass of {@link LibFunction} which implements the lua standard {@code math}
@@ -77,75 +80,161 @@ public class MathLib extends OneArgFunction {
public static MathLib MATHLIB = null; public static MathLib MATHLIB = null;
private Random random;
public MathLib() { public MathLib() {
MATHLIB = this; MATHLIB = this;
} }
public LuaValue call(LuaValue env) { public LuaValue call(LuaValue env) {
LuaTable t = new LuaTable(0,30); LuaTable math = new LuaTable(0,30);
t.set( "pi", Math.PI ); math.set("abs", new abs());
t.set( "huge", LuaDouble.POSINF ); math.set("ceil", new ceil());
bind( t, MathLib1.class, new String[] { math.set("cos", new cos());
"abs", "ceil", "cos", "deg", math.set("deg", new deg());
"exp", "floor", "rad", "sin", math.set("exp", new exp(this));
"sqrt", "tan" } ); math.set("floor", new floor());
bind( t, MathLib2.class, new String[] { math.set("fmod", new fmod());
"fmod", "ldexp", "pow", } ); math.set("frexp", new frexp());
bind( t, MathLibV.class, new String[] { math.set("huge", LuaDouble.POSINF );
"frexp", "max", "min", "modf", math.set("ldexp", new ldexp());
"randomseed", "random", } ); math.set("max", new max());
((MathLibV) t.get("randomseed")).mathlib = this; math.set("min", new min());
((MathLibV) t.get("random" )).mathlib = this; math.set("modf", new modf());
env.set("math", t); math.set("pi", Math.PI );
PackageLib.instance.LOADED.set("math", t); math.set("pow", new pow());
return t; random r;
math.set("random", r = new random());
math.set("randomseed", new randomseed(r));
math.set("rad", new rad());
math.set("sin", new sin());
math.set("sqrt", new sqrt());
math.set("tan", new tan());
env.set("math", math);
PackageLib.instance.LOADED.set("math", math);
return math;
}
abstract protected static class UnaryOp extends OneArgFunction {
public LuaValue call(LuaValue arg) {
return valueOf(call(arg.checkdouble()));
}
abstract protected double call(double d);
} }
static final class MathLib1 extends OneArgFunction { abstract protected static class BinaryOp extends TwoArgFunction {
public LuaValue call(LuaValue arg) { public LuaValue call(LuaValue x, LuaValue y) {
switch ( opcode ) { return valueOf(call(x.checkdouble(), y.checkdouble()));
case 0: return valueOf(Math.abs(arg.checkdouble())); }
case 1: return valueOf(Math.ceil(arg.checkdouble())); abstract protected double call(double x, double y);
case 2: return valueOf(Math.cos(arg.checkdouble())); }
case 3: return valueOf(Math.toDegrees(arg.checkdouble()));
case 4: return dpow(Math.E,arg.checkdouble()); static final class abs extends UnaryOp { protected double call(double d) { return Math.abs(d); } }
case 5: return valueOf(Math.floor(arg.checkdouble())); static final class ceil extends UnaryOp { protected double call(double d) { return Math.ceil(d); } }
case 6: return valueOf(Math.toRadians(arg.checkdouble())); static final class cos extends UnaryOp { protected double call(double d) { return Math.cos(d); } }
case 7: return valueOf(Math.sin(arg.checkdouble())); static final class deg extends UnaryOp { protected double call(double d) { return Math.toDegrees(d); } }
case 8: return valueOf(Math.sqrt(arg.checkdouble())); static final class floor extends UnaryOp { protected double call(double d) { return Math.floor(d); } }
case 9: return valueOf(Math.tan(arg.checkdouble())); static final class rad extends UnaryOp { protected double call(double d) { return Math.toRadians(d); } }
} static final class sin extends UnaryOp { protected double call(double d) { return Math.sin(d); } }
return NIL; static final class sqrt extends UnaryOp { protected double call(double d) { return Math.sqrt(d); } }
static final class tan extends UnaryOp { protected double call(double d) { return Math.tan(d); } }
static final class exp extends UnaryOp {
final MathLib mathlib;
exp(MathLib mathlib) {
this.mathlib = mathlib;
}
protected double call(double d) {
return mathlib.dpow_lib(Math.E,d);
}
}
static final class fmod extends BinaryOp {
protected double call(double x, double y) {
double q = x/y;
return x - y * (q>=0? Math.floor(q): Math.ceil(q));
}
}
static final class ldexp extends BinaryOp {
protected double call(double x, double y) {
y += 1023.5;
long e = (long) ((0!=(1&((int)y)))? Math.floor(y): Math.ceil(y-1));
return x * Double.longBitsToDouble(e << 52);
}
}
static final class pow extends BinaryOp {
protected double call(double x, double y) {
return MathLib.dpow_default(x, y);
}
}
static class frexp extends VarArgFunction {
public Varargs invoke(Varargs args) {
double x = args.checkdouble(1);
if ( x == 0 ) return varargsOf(ZERO,ZERO);
long bits = Double.doubleToLongBits( x );
double m = ((bits & (~(-1L<<52))) + (1L<<52)) * ((bits >= 0)? (.5 / (1L<<52)): (-.5 / (1L<<52)));
double e = (((int) (bits >> 52)) & 0x7ff) - 1022;
return varargsOf( valueOf(m), valueOf(e) );
}
}
static class max extends VarArgFunction {
public Varargs invoke(Varargs args) {
double m = args.checkdouble(1);
for ( int i=2,n=args.narg(); i<=n; ++i )
m = Math.max(m,args.checkdouble(i));
return valueOf(m);
} }
} }
static final class MathLib2 extends TwoArgFunction { static class min extends VarArgFunction {
protected MathLib mathlib; public Varargs invoke(Varargs args) {
public LuaValue call(LuaValue arg1, LuaValue arg2) { double m = args.checkdouble(1);
switch ( opcode ) { for ( int i=2,n=args.narg(); i<=n; ++i )
case 0: { // fmod m = Math.min(m,args.checkdouble(i));
double x = arg1.checkdouble(); return valueOf(m);
double y = arg2.checkdouble();
double q = x/y;
double f = x - y * (q>=0? Math.floor(q): Math.ceil(q));
return valueOf( f );
}
case 1: { // ldexp
double x = arg1.checkdouble();
double y = arg2.checkdouble()+1023.5;
long e = (long) ((0!=(1&((int)y)))? Math.floor(y): Math.ceil(y-1));
return valueOf(x * Double.longBitsToDouble(e << 52));
}
case 2: { // pow
return dpow(arg1.checkdouble(), arg2.checkdouble());
}
}
return NIL;
} }
} }
static class modf extends VarArgFunction {
public Varargs invoke(Varargs args) {
double x = args.checkdouble(1);
double intPart = ( x > 0 ) ? Math.floor( x ) : Math.ceil( x );
double fracPart = x - intPart;
return varargsOf( valueOf(intPart), valueOf(fracPart) );
}
}
static class random extends LibFunction {
Random random = new Random();
public LuaValue call() {
return valueOf( random.nextDouble() );
}
public LuaValue call(LuaValue a) {
int m = a.checkint();
if (m<1) argerror(1, "interval is empty");
return valueOf( 1 + random.nextInt(m) );
}
public LuaValue call(LuaValue a, LuaValue b) {
int m = a.checkint();
int n = b.checkint();
if (n<m) argerror(2, "interval is empty");
return valueOf( m + random.nextInt(n+1-m) );
}
}
static class randomseed extends OneArgFunction {
final random random;
randomseed(random random) {
this.random = random;
}
public LuaValue call(LuaValue arg) {
long seed = arg.checklong();
random.random = new Random(seed);
return NONE;
}
}
/** compute power using installed math library, or default if there is no math library installed */ /** compute power using installed math library, or default if there is no math library installed */
public static LuaValue dpow(double a, double b) { public static LuaValue dpow(double a, double b) {
return LuaDouble.valueOf( return LuaDouble.valueOf(
@@ -188,63 +277,4 @@ public class MathLib extends OneArgFunction {
return p; return p;
} }
static final class MathLibV extends VarArgFunction {
protected MathLib mathlib;
public Varargs invoke(Varargs args) {
switch ( opcode ) {
case 0: { // frexp
double x = args.checkdouble(1);
if ( x == 0 ) return varargsOf(ZERO,ZERO);
long bits = Double.doubleToLongBits( x );
double m = ((bits & (~(-1L<<52))) + (1L<<52)) * ((bits >= 0)? (.5 / (1L<<52)): (-.5 / (1L<<52)));
double e = (((int) (bits >> 52)) & 0x7ff) - 1022;
return varargsOf( valueOf(m), valueOf(e) );
}
case 1: { // max
double m = args.checkdouble(1);
for ( int i=2,n=args.narg(); i<=n; ++i )
m = Math.max(m,args.checkdouble(i));
return valueOf(m);
}
case 2: { // min
double m = args.checkdouble(1);
for ( int i=2,n=args.narg(); i<=n; ++i )
m = Math.min(m,args.checkdouble(i));
return valueOf(m);
}
case 3: { // modf
double x = args.checkdouble(1);
double intPart = ( x > 0 ) ? Math.floor( x ) : Math.ceil( x );
double fracPart = x - intPart;
return varargsOf( valueOf(intPart), valueOf(fracPart) );
}
case 4: { // randomseed
long seed = args.checklong(1);
mathlib.random = new Random(seed);
return NONE;
}
case 5: { // random
if ( mathlib.random == null )
mathlib.random = new Random();
switch ( args.narg() ) {
case 0:
return valueOf( mathlib.random.nextDouble() );
case 1: {
int m = args.checkint(1);
if (m<1) argerror(1, "interval is empty");
return valueOf( 1 + mathlib.random.nextInt(m) );
}
default: {
int m = args.checkint(1);
int n = args.checkint(2);
if (n<m) argerror(2, "interval is empty");
return valueOf( m + mathlib.random.nextInt(n+1-m) );
}
}
}
}
return NONE;
}
}
} }

View File

@@ -23,8 +23,6 @@ package org.luaj.vm2.lib.jse;
import org.luaj.vm2.LuaValue; import org.luaj.vm2.LuaValue;
import org.luaj.vm2.lib.LibFunction; import org.luaj.vm2.lib.LibFunction;
import org.luaj.vm2.lib.OneArgFunction;
import org.luaj.vm2.lib.TwoArgFunction;
/** /**
* Subclass of {@link LibFunction} which implements the lua standard {@code math} * Subclass of {@link LibFunction} which implements the lua standard {@code math}
@@ -60,42 +58,32 @@ public class JseMathLib extends org.luaj.vm2.lib.MathLib {
public JseMathLib() {} public JseMathLib() {}
public LuaValue call(LuaValue arg) { public LuaValue call(LuaValue env) {
LuaValue t = super.call(arg); super.call(env);
bind( t, JseMathLib1.class, new String[] { LuaValue math = env.get("math");
"acos", "asin", "atan", "cosh", math.set("acos", new acos());
"exp", "log", "sinh", math.set("asin", new asin());
"tanh" } ); math.set("atan", new atan());
bind( t, JseMathLib2.class, new String[] { math.set("atan2", new atan2());
"atan2", "pow", } ); math.set("cosh", new cosh());
return t; math.set("exp", new exp());
math.set("log", new log());
math.set("pow", new pow());
math.set("sinh", new sinh());
math.set("tanh", new tanh());
return math;
} }
public static final class JseMathLib1 extends OneArgFunction { static final class acos extends UnaryOp { protected double call(double d) { return Math.acos(d); } }
public LuaValue call(LuaValue arg) { static final class asin extends UnaryOp { protected double call(double d) { return Math.asin(d); } }
switch ( opcode ) { static final class atan extends UnaryOp { protected double call(double d) { return Math.atan(d); } }
case 0: return valueOf(Math.acos(arg.checkdouble())); static final class atan2 extends BinaryOp { protected double call(double y, double x) { return Math.atan2(y, x); } }
case 1: return valueOf(Math.asin(arg.checkdouble())); static final class cosh extends UnaryOp { protected double call(double d) { return Math.cosh(d); } }
case 2: return valueOf(Math.atan(arg.checkdouble())); static final class exp extends UnaryOp { protected double call(double d) { return Math.exp(d); } }
case 3: return valueOf(Math.cosh(arg.checkdouble())); static final class log extends UnaryOp { protected double call(double d) { return Math.log(d); } }
case 4: return valueOf(Math.exp(arg.checkdouble())); static final class pow extends BinaryOp { protected double call(double x, double y) { return Math.pow(x, y); } }
case 5: return valueOf(Math.log(arg.checkdouble())); static final class sinh extends UnaryOp { protected double call(double d) { return Math.sinh(d); } }
case 6: return valueOf(Math.sinh(arg.checkdouble())); static final class tanh extends UnaryOp { protected double call(double d) { return Math.tanh(d); } }
case 7: return valueOf(Math.tanh(arg.checkdouble()));
}
return NIL;
}
}
public static final class JseMathLib2 extends TwoArgFunction {
public LuaValue call(LuaValue arg1, LuaValue arg2) {
switch ( opcode ) {
case 0: return valueOf(Math.atan2(arg1.checkdouble(), arg2.checkdouble()));
case 1: return valueOf(Math.pow(arg1.checkdouble(), arg2.checkdouble()));
}
return NIL;
}
}
/** Faster, better version of pow() used by arithmetic operator ^ */ /** Faster, better version of pow() used by arithmetic operator ^ */
public double dpow_lib(double a, double b) { public double dpow_lib(double a, double b) {

View File

@@ -19,7 +19,7 @@ local singleargfunctions = {
} }
local singleargposdomain = { local singleargposdomain = {
'log', 'log10', 'sqrt', 'ceil', 'log', 'sqrt', 'ceil',
} }
local twoargfunctions = { local twoargfunctions = {

View File

@@ -76,7 +76,7 @@ local ONEARG_JME = {
} }
local ONEARG_JSE = { local ONEARG_JSE = {
"acos", "asin", "atan", "cosh", "acos", "asin", "atan", "cosh",
"log", "log10", "sinh", "tanh", "log", "sinh", "tanh",
} }
local TWOARGS_JME = { local TWOARGS_JME = {
"fmod", "ldexp", "pow", "fmod", "ldexp", "pow",

View File

@@ -24,7 +24,7 @@ for DIR in "errors" "perf" "."; do
FILES=`ls -1 *.lua | awk 'BEGIN { FS="." } ; { print $1 }'` FILES=`ls -1 *.lua | awk 'BEGIN { FS="." } ; { print $1 }'`
for FILE in $FILES ; do for FILE in $FILES ; do
echo 'executing' `pwd` $FILE echo 'executing' `pwd` $FILE
lua ${FILE}.lua > ${FILE}.out lua ${FILE}.lua JSE > ${FILE}.out
done done
cd .. cd ..
done done