Refactor math support to build for cldc 1.1.

This commit is contained in:
James Roseborough
2008-07-22 17:50:31 +00:00
parent 9113435e57
commit eae183e334
10 changed files with 214 additions and 141 deletions

View File

@@ -842,7 +842,7 @@ public class FuncState extends LuaC {
r = (LNumber) v2.luaBinOpUnknown(op, v1);
break;
case OP_POW:
r = Platform.getInstance().mathPow( v1.toJavaDouble(), v2.toJavaDouble() );
r = Platform.getInstance().mathPow( v1, v2 );
break;
case OP_UNM:
r = (LNumber) v1.luaUnaryMinus();

View File

@@ -26,6 +26,7 @@ import java.util.Random;
import org.luaj.vm.LDouble;
import org.luaj.vm.LFunction;
import org.luaj.vm.LInteger;
import org.luaj.vm.LNumber;
import org.luaj.vm.LTable;
import org.luaj.vm.LValue;
import org.luaj.vm.LuaState;
@@ -143,12 +144,17 @@ public class MathLib extends LFunction {
vm.resettop();
vm.pushlvalue( LInteger.valueOf(i) );
}
private static void setResult(LuaState vm, LNumber mathop) {
vm.resettop();
vm.pushlvalue( mathop );
}
public boolean luaStackCall( LuaState vm ) {
if ( id > LAST_DOUBLE_ARG ) {
setResult( vm, platform.mathop(id, vm.checkdouble(2) ) );
setResult( vm, platform.mathop(id, vm.checknumber(2) ) );
} else if ( id > LAST_IRREGULAR ) {
setResult( vm, platform.mathop(id, vm.checkdouble(2), vm.checkdouble(3) ) );
setResult( vm, platform.mathop(id, vm.checknumber(2), vm.checknumber(3) ) );
} else {
switch ( id ) {
case INSTALL:
@@ -235,5 +241,4 @@ public class MathLib extends LFunction {
}
return false;
}
}

View File

@@ -205,7 +205,7 @@ public class TableLib extends LFunction {
*/
case SORT: {
LTable table = vm.checktable(2);
LValue compare = (vm.isnoneornil(3)? LNil.NIL: vm.checkfunction(3));
LValue compare = (vm.isnoneornil(3)? (LValue) LNil.NIL: (LValue) vm.checkfunction(3));
table.luaSort( vm, compare );
vm.resettop();
break;

View File

@@ -29,6 +29,12 @@ public class LDouble extends LNumber {
public static LDouble valueOf(double value) {
return new LDouble(value);
}
/** Convert to LNumber, using LInteger if possible */
public static LNumber numberOf(double z) {
int iz = (int) z;
return (z==iz? (LNumber) LInteger.valueOf(iz): (LNumber) new LDouble(z));
}
public LDouble(double value) {
this.m_value = value;
@@ -82,12 +88,12 @@ public class LDouble extends LNumber {
public static LValue luaBinOpDoubleDouble( int opcode, double lhs, double rhs ) {
switch ( opcode ) {
case Lua.OP_ADD: return new LDouble( lhs + rhs );
case Lua.OP_SUB: return new LDouble( lhs - rhs );
case Lua.OP_MUL: return new LDouble( lhs * rhs );
case Lua.OP_DIV: return new LDouble( lhs / rhs );
case Lua.OP_MOD: return new LDouble( lhs - Math.floor(lhs/rhs) * rhs );
case Lua.OP_POW: return Platform.getInstance().mathPow(lhs, rhs);
case Lua.OP_ADD: return LDouble.numberOf( lhs + rhs );
case Lua.OP_SUB: return LDouble.numberOf( lhs - rhs );
case Lua.OP_MUL: return LDouble.numberOf( lhs * rhs );
case Lua.OP_DIV: return LDouble.numberOf( lhs / rhs );
case Lua.OP_MOD: return LDouble.numberOf( lhs - Math.floor(lhs/rhs) * rhs );
case Lua.OP_POW: return Platform.getInstance().mathPow( LDouble.valueOf(lhs), LDouble.valueOf(rhs));
}
LuaState.vmerror( "bad bin opcode" );
return null;
@@ -131,5 +137,4 @@ public class LDouble extends LNumber {
public LValue luaUnaryMinus() {
return new LDouble( -m_value );
}
}

View File

@@ -82,6 +82,6 @@ public class LuaErrorException extends RuntimeException {
else
vm = LuaState.mainState;
}
return vm.getFileLine(vm.cc + 1 - level) + ": " + message;
return vm != null? vm.getFileLine(vm.cc + 1 - level) + ": " + message: message;
}
}

View File

@@ -146,14 +146,6 @@ abstract public class Platform {
*/
abstract protected void installOptionalLibs(LuaState vm);
/**
* Compute math.pow() for two numbers using double math when available.
* @param lhs LNumber base
* @param rhs LNumber exponent
* @return base ^ exponent as a LNumber, throw RuntimeException if not implemented
*/
abstract public LNumber mathPow(double lhs, double rhs);
/**
* Convenience method for the subclasses to figure out the debug host.
* @return the debug host property. If it is not present, null is returned.
@@ -179,22 +171,37 @@ abstract public class Platform {
return port;
}
/**
* Compute math.pow() for two numbers using double math when available.
* @param lhs LNumber base
* @param rhs LNumber exponent
* @return base ^ exponent as a LNumber, throw RuntimeException if not implemented
*/
abstract public LNumber mathPow(LNumber base, LNumber exponent);
/**
* Compute a math operation that takes a single double argument and returns a double
* @param id the math op, from MathLib constants
* @param x the arugment
* @return the value
* @param x the argument
* @return the value as an LNumber
* @throws LuaErrorException if the id is not supported by this platform.
*/
abstract public double mathop(int id, double x);
abstract public LNumber mathop(int id, LNumber x);
/**
* Compute a math operation that takes a two double arguments and returns a double
* @param id the math op, from MathLib constants
* @param x the first arugment
* @param y the second arugment
* @return the value
* @param x the first argument as an LNumber
* @param y the second arugment as an LNumber
* @return the value as an LNumber
* @throws LuaErrorException if the id is not supported by this platform.
*/
abstract public double mathop(int id, double x, double y);
abstract public LNumber mathop(int id, LNumber x, LNumber y);
/** Throw an error indicating the math operation is not accepted */
public LNumber unsupportedMathOp() {
throw new LuaErrorException("math op not supported on "+getName());
}
}

View File

@@ -51,65 +51,16 @@ public class J2meMidp10Cldc10Platform extends Platform {
protected void installOptionalLibs(LuaState vm) {
vm.installStandardLibs();
}
public LNumber mathPow(double lhs, double rhs) {
return LDouble.valueOf(dpow(lhs,rhs));
}
public double mathop(int id, double a, double b) {
switch ( id ) {
case MathLib.ATAN2: return
b>0? Math.atan(a/b):
b<0? (a>=0? Math.PI-Math.atan(a/-b): -Math.PI-Math.atan(a/-b)):
(a>0? Math.PI/2: a<0? -Math.PI/2: 0);
case MathLib.FMOD: return a - (b * ((int)(a/b)));
case MathLib.POW: return dpow(a, b);
}
throw new LuaErrorException( "unsupported math op" );
public LNumber mathPow(LNumber base, LNumber exponent) {
return unsupportedMathOp();
}
public double mathop(int id, double x) {
switch ( id ) {
case MathLib.ABS: return Math.abs(x);
//case MathLib.ACOS: return Math.acos(x);
//case MathLib.ASIN: return Math.asin(x);
//case MathLib.ATAN: return Math.atan(x);
case MathLib.COS: return Math.cos(x);
case MathLib.COSH: return (Math.exp(x) + Math.exp(-x)) / 2;
case MathLib.DEG: return Math.toDegrees(x);
case MathLib.EXP: return Math.exp(x);
case MathLib.LOG: return Math.log(x);
case MathLib.LOG10: return Math.log10(x);
case MathLib.RAD: return Math.toRadians(x);
case MathLib.SIN: return Math.sin(x);
case MathLib.SINH: return (Math.exp(x) - Math.exp(-x)) / 2;
case MathLib.SQRT: return Math.sqrt(x);
case MathLib.TAN: return Math.tan(x);
case MathLib.TANH: {
double e = Math.exp(2*x);
return (e-1) / (e+1);
}
}
throw new LuaErrorException( "unsupported math op" );
public LNumber mathop(int id, LNumber x, LNumber y) {
return unsupportedMathOp();
}
public static double dpow(double a, double b) {
if ( b < 0 )
return 1 / dpow( a, -b );
double p = 1;
int whole = (int) b;
for ( double v=a; whole > 0; whole>>=1, v*=v )
if ( (whole & 1) != 0 )
p *= v;
if ( (b -= whole) > 0 ) {
int frac = (int) (0x10000 * b);
for ( ; (frac&0xffff)!=0; frac<<=1 ) {
a = Math.sqrt(a);
if ( (frac & 0x8000) != 0 )
p *= a;
}
}
return p;
public LNumber mathop(int id, LNumber x) {
return unsupportedMathOp();
}
}

View File

@@ -2,8 +2,83 @@ package org.luaj.platform;
import javax.microedition.midlet.MIDlet;
import org.luaj.lib.MathLib;
import org.luaj.vm.LDouble;
import org.luaj.vm.LNumber;
public class J2meMidp20Cldc11Platform extends J2meMidp10Cldc10Platform {
public J2meMidp20Cldc11Platform(MIDlet midlet) {
super(midlet);
}
public LNumber mathPow(LNumber base, LNumber exp) {
return LDouble.numberOf(dpow(base.toJavaDouble(),exp.toJavaDouble()));
}
public LNumber mathop(int id, LNumber la, LNumber lb) {
double a = la.toJavaDouble();
double b = lb.toJavaDouble();
double z = 0;
switch ( id ) {
default: return unsupportedMathOp();
//case MathLib.ATAN2: z =
// b>0? Math.atan(a/b):
// b<0? (a>=0? Math.PI-Math.atan(a/-b): -Math.PI-Math.atan(a/-b)):
// (a>0? Math.PI/2: a<0? -Math.PI/2: 0);
// break;
case MathLib.FMOD: z = a - (b * ((int)(a/b))); break;
case MathLib.POW: z = dpow(a, b); break;
}
return LDouble.numberOf(z);
}
public LNumber mathop(int id, LNumber lx) {
double x = lx.toJavaDouble();
double z = 0;
switch ( id ) {
default: return unsupportedMathOp();
case MathLib.ABS: z = Math.abs(x); break;
//case MathLib.ACOS: z = Math.acos(x); break;
//case MathLib.ASIN: z = Math.asin(x); break;
//case MathLib.ATAN: z = Math.atan(x); break;
case MathLib.COS: z = Math.cos(x); break;
//case MathLib.COSH: z = (Math.exp(x) + Math.exp(-x)) / 2; break;
case MathLib.DEG: z = Math.toDegrees(x); break;
//case MathLib.EXP: z = Math.exp(x); break;
//case MathLib.LOG: z = Math.log(x); break;
//case MathLib.LOG10: z = Math.log10(x); break;
case MathLib.RAD: z = Math.toRadians(x); break;
case MathLib.SIN: z = Math.sin(x); break;
//case MathLib.SINH: z = (Math.exp(x) - Math.exp(-x)) / 2; break;
case MathLib.SQRT: z = Math.sqrt(x); break;
case MathLib.TAN: z = Math.tan(x); break;
//case MathLib.TANH: {
// double e = Math.exp(2*x);
// z = (e-1) / (e+1);
// break;
//}
}
return LDouble.numberOf(z);
}
public static double dpow(double a, double b) {
if ( b < 0 )
return 1 / dpow( a, -b );
double p = 1;
int whole = (int) b;
for ( double v=a; whole > 0; whole>>=1, v*=v )
if ( (whole & 1) != 0 )
p *= v;
if ( (b -= whole) > 0 ) {
int frac = (int) (0x10000 * b);
for ( ; (frac&0xffff)!=0; frac<<=1 ) {
a = Math.sqrt(a);
if ( (frac & 0x8000) != 0 )
p *= a;
}
}
return p;
}
}

View File

@@ -52,39 +52,45 @@ public class J2sePlatform extends Platform {
}
}
public LNumber mathPow(double lhs, double rhs) {
double d = Math.pow(lhs, rhs);
return LDouble.valueOf(d);
public LNumber mathPow(LNumber base, LNumber exp) {
return LDouble.numberOf(Math.pow(base.toJavaDouble(),exp.toJavaDouble()));
}
public double mathop(int id, double a, double b) {
public LNumber mathop(int id, LNumber la, LNumber lb) {
double a = la.toJavaDouble();
double b = lb.toJavaDouble();
double z = 0;
switch ( id ) {
case MathLib.ATAN2: return Math.atan2(a, b);
case MathLib.FMOD: return a - (b * ((int)(a/b)));
case MathLib.POW: return Math.pow(a, b);
default: return unsupportedMathOp();
case MathLib.ATAN2: z = Math.atan2(a, b); break;
case MathLib.FMOD: z = a - (b * ((int)(a/b))); break;
case MathLib.POW: z = Math.pow(a, b); break;
}
throw new LuaErrorException( "unsupported math op" );
return LDouble.numberOf(z);
}
public double mathop(int id, double x) {
public LNumber mathop(int id, LNumber lx) {
double x = lx.toJavaDouble();
double z = 0;
switch ( id ) {
case MathLib.ABS: return Math.abs(x);
case MathLib.ACOS: return Math.acos(x);
case MathLib.ASIN: return Math.asin(x);
case MathLib.ATAN: return Math.atan(x);
case MathLib.COS: return Math.cos(x);
case MathLib.COSH: return Math.cosh(x);
case MathLib.DEG: return Math.toDegrees(x);
case MathLib.EXP: return Math.exp(x);
case MathLib.LOG: return Math.log(x);
case MathLib.LOG10: return Math.log10(x);
case MathLib.RAD: return Math.toRadians(x);
case MathLib.SIN: return Math.sin(x);
case MathLib.SINH: return Math.sinh(x);
case MathLib.SQRT: return Math.sqrt(x);
case MathLib.TAN: return Math.tan(x);
case MathLib.TANH: return Math.tanh(x);
default: return unsupportedMathOp();
case MathLib.ABS: z = Math.abs(x); break;
case MathLib.ACOS: z = Math.acos(x); break;
case MathLib.ASIN: z = Math.asin(x); break;
case MathLib.ATAN: z = Math.atan(x); break;
case MathLib.COS: z = Math.cos(x); break;
case MathLib.COSH: z = Math.cosh(x); break;
case MathLib.DEG: z = Math.toDegrees(x); break;
case MathLib.EXP: z = Math.exp(x); break;
case MathLib.LOG: z = Math.log(x); break;
case MathLib.LOG10: z = Math.log10(x); break;
case MathLib.RAD: z = Math.toRadians(x); break;
case MathLib.SIN: z = Math.sin(x); break;
case MathLib.SINH: z = Math.sinh(x); break;
case MathLib.SQRT: z = Math.sqrt(x); break;
case MathLib.TAN: z = Math.tan(x); break;
case MathLib.TANH: z = Math.tanh(x); break;
}
throw new LuaErrorException( "unsupported math op" );
return LDouble.numberOf(z);
}
}

View File

@@ -3,40 +3,42 @@ package org.luaj.vm;
import junit.framework.TestCase;
import org.luaj.lib.MathLib;
import org.luaj.platform.J2meMidp10Cldc10Platform;
import org.luaj.platform.J2meMidp20Cldc11Platform;
import org.luaj.platform.J2sePlatform;
public class MathLibTest extends TestCase {
private Platform j2se;
private Platform j2me;
private boolean supportedOnJ2me;
protected void setUp() throws Exception {
j2se = new J2sePlatform();
j2me = new org.luaj.platform.J2meMidp10Cldc10Platform(null);
j2me = new org.luaj.platform.J2meMidp20Cldc11Platform(null);
supportedOnJ2me = true;
}
public void testMathDPow() {
assertEquals( 1, J2meMidp10Cldc10Platform.dpow(2, 0), 0 );
assertEquals( 2, J2meMidp10Cldc10Platform.dpow(2, 1), 0 );
assertEquals( 8, J2meMidp10Cldc10Platform.dpow(2, 3), 0 );
assertEquals( -8, J2meMidp10Cldc10Platform.dpow(-2, 3), 0 );
assertEquals( 1/8., J2meMidp10Cldc10Platform.dpow(2, -3), 0 );
assertEquals( -1/8., J2meMidp10Cldc10Platform.dpow(-2, -3), 0 );
assertEquals( 16, J2meMidp10Cldc10Platform.dpow(256, .5), 0 );
assertEquals( 4, J2meMidp10Cldc10Platform.dpow(256, .25), 0 );
assertEquals( 64, J2meMidp10Cldc10Platform.dpow(256, .75), 0 );
assertEquals( 1./16, J2meMidp10Cldc10Platform.dpow(256, - .5), 0 );
assertEquals( 1./ 4, J2meMidp10Cldc10Platform.dpow(256, -.25), 0 );
assertEquals( 1./64, J2meMidp10Cldc10Platform.dpow(256, -.75), 0 );
assertEquals( Double.NaN, J2meMidp10Cldc10Platform.dpow(-256, .5), 0 );
assertEquals( 1, J2meMidp10Cldc10Platform.dpow(.5, 0), 0 );
assertEquals( .5, J2meMidp10Cldc10Platform.dpow(.5, 1), 0 );
assertEquals(.125, J2meMidp10Cldc10Platform.dpow(.5, 3), 0 );
assertEquals( 2, J2meMidp10Cldc10Platform.dpow(.5, -1), 0 );
assertEquals( 8, J2meMidp10Cldc10Platform.dpow(.5, -3), 0 );
assertEquals(1, J2meMidp10Cldc10Platform.dpow(0.0625, 0), 0 );
assertEquals(0.00048828125, J2meMidp10Cldc10Platform.dpow(0.0625, 2.75), 0 );
assertEquals( 1, J2meMidp20Cldc11Platform.dpow(2, 0), 0 );
assertEquals( 2, J2meMidp20Cldc11Platform.dpow(2, 1), 0 );
assertEquals( 8, J2meMidp20Cldc11Platform.dpow(2, 3), 0 );
assertEquals( -8, J2meMidp20Cldc11Platform.dpow(-2, 3), 0 );
assertEquals( 1/8., J2meMidp20Cldc11Platform.dpow(2, -3), 0 );
assertEquals( -1/8., J2meMidp20Cldc11Platform.dpow(-2, -3), 0 );
assertEquals( 16, J2meMidp20Cldc11Platform.dpow(256, .5), 0 );
assertEquals( 4, J2meMidp20Cldc11Platform.dpow(256, .25), 0 );
assertEquals( 64, J2meMidp20Cldc11Platform.dpow(256, .75), 0 );
assertEquals( 1./16, J2meMidp20Cldc11Platform.dpow(256, - .5), 0 );
assertEquals( 1./ 4, J2meMidp20Cldc11Platform.dpow(256, -.25), 0 );
assertEquals( 1./64, J2meMidp20Cldc11Platform.dpow(256, -.75), 0 );
assertEquals( Double.NaN, J2meMidp20Cldc11Platform.dpow(-256, .5), 0 );
assertEquals( 1, J2meMidp20Cldc11Platform.dpow(.5, 0), 0 );
assertEquals( .5, J2meMidp20Cldc11Platform.dpow(.5, 1), 0 );
assertEquals(.125, J2meMidp20Cldc11Platform.dpow(.5, 3), 0 );
assertEquals( 2, J2meMidp20Cldc11Platform.dpow(.5, -1), 0 );
assertEquals( 8, J2meMidp20Cldc11Platform.dpow(.5, -3), 0 );
assertEquals(1, J2meMidp20Cldc11Platform.dpow(0.0625, 0), 0 );
assertEquals(0.00048828125, J2meMidp20Cldc11Platform.dpow(0.0625, 2.75), 0 );
}
public void testAbs() {
@@ -49,6 +51,7 @@ public class MathLibTest extends TestCase {
}
public void testCosh() {
supportedOnJ2me = false;
tryTrigOps( MathLib.COSH );
}
@@ -57,6 +60,7 @@ public class MathLibTest extends TestCase {
}
public void testExp() {
supportedOnJ2me = false;
tryMathOp( MathLib.EXP, 0 );
tryMathOp( MathLib.EXP, 0.1 );
tryMathOp( MathLib.EXP, .9 );
@@ -69,6 +73,7 @@ public class MathLibTest extends TestCase {
}
public void testLog() {
supportedOnJ2me = false;
tryMathOp( MathLib.LOG, 0.1 );
tryMathOp( MathLib.LOG, .9 );
tryMathOp( MathLib.LOG, 1. );
@@ -80,6 +85,7 @@ public class MathLibTest extends TestCase {
}
public void testLog10() {
supportedOnJ2me = false;
tryMathOp( MathLib.LOG10, 0.1 );
tryMathOp( MathLib.LOG10, .9 );
tryMathOp( MathLib.LOG10, 1. );
@@ -115,6 +121,7 @@ public class MathLibTest extends TestCase {
}
public void testSinh() {
supportedOnJ2me = false;
tryTrigOps( MathLib.SINH );
}
@@ -132,10 +139,12 @@ public class MathLibTest extends TestCase {
}
public void testTanh() {
supportedOnJ2me = false;
tryTrigOps( MathLib.TANH );
}
public void testAtan2() {
supportedOnJ2me = false;
tryDoubleOps( MathLib.ATAN2, false );
}
@@ -202,17 +211,32 @@ public class MathLibTest extends TestCase {
tryMathOp( id, -Math.PI*9/8 );
}
private void tryMathOp(int id, double x) {
double expected = j2se.mathop(id, x);
double actual = j2me.mathop(id, x);
assertEquals( expected, actual, 1.e-5 );
private void tryMathOp(int id, double x) {
try {
double expected = j2se.mathop(id, LDouble.valueOf(x)).toJavaDouble();
double actual = j2me.mathop(id, LDouble.valueOf(x)).toJavaDouble();
if ( supportedOnJ2me )
assertEquals( expected, actual, 1.e-5 );
else
this.fail("j2me should throw exception for math op "+id+" but returned "+actual);
} catch ( LuaErrorException lee ) {
if ( supportedOnJ2me )
throw lee;
}
}
private void tryMathOp(int id, double a, double b) {
double expected = j2se.mathop(id, a, b);
double actual = j2me.mathop(id, a, b);
assertEquals( expected, actual, 1.e-5 );
}
try {
double expected = j2se.mathop(id, LDouble.valueOf(a), LDouble.valueOf(b)).toJavaDouble();
double actual = j2me.mathop(id, LDouble.valueOf(a), LDouble.valueOf(b)).toJavaDouble();
if ( supportedOnJ2me )
assertEquals( expected, actual, 1.e-5 );
else
this.fail("j2me should throw exception for math op "+id+" but returned "+actual);
} catch ( LuaErrorException lee ) {
if ( supportedOnJ2me )
throw lee;
}
}
}