nl.weeaboo.lua2.stdlib.MathLib Maven / Gradle / Ivy
package nl.weeaboo.lua2.stdlib;
import static nl.weeaboo.lua2.vm.LuaConstants.NONE;
import static nl.weeaboo.lua2.vm.LuaValue.argerror;
import static nl.weeaboo.lua2.vm.LuaValue.valueOf;
import static nl.weeaboo.lua2.vm.LuaValue.varargsOf;
import java.util.Random;
import nl.weeaboo.lua2.LuaException;
import nl.weeaboo.lua2.io.LuaSerializable;
import nl.weeaboo.lua2.lib.LuaBoundFunction;
import nl.weeaboo.lua2.vm.LuaDouble;
import nl.weeaboo.lua2.vm.LuaInteger;
import nl.weeaboo.lua2.vm.LuaTable;
import nl.weeaboo.lua2.vm.Varargs;
/**
* Math library
*/
@LuaSerializable
public final class MathLib extends LuaModule {
private static final long serialVersionUID = 1L;
private final Random random = new Random();
MathLib() {
super("math");
}
@Override
protected void registerAdditional(LuaTable globals, LuaTable libTable) throws LuaException {
super.registerAdditional(globals, globals);
libTable.set("pi", Math.PI);
libTable.set("huge", LuaDouble.POSINF);
}
/**
* math.abs (x)
*
* Returns the absolute value of x.
*/
@LuaBoundFunction
public Varargs abs(Varargs args) {
return valueOf(Math.abs(args.checkdouble(1)));
}
/**
* math.ceil (x)
*
* Returns the smallest integer larger than or equal to x.
*/
@LuaBoundFunction
public Varargs ceil(Varargs args) {
return valueOf(Math.ceil(args.checkdouble(1)));
}
/**
* math.cos (x)
*
* Returns the cosine of x (assumed to be in radians).
*/
@LuaBoundFunction
public Varargs cos(Varargs args) {
return valueOf(Math.cos(args.checkdouble(1)));
}
/**
* math.deg (x)
*
* Returns the angle x (given in radians) in degrees.
*/
@LuaBoundFunction
public Varargs deg(Varargs args) {
return valueOf(Math.toDegrees(args.checkdouble(1)));
}
/**
* math.exp (x)
*
* Returns the value ex.
*/
@LuaBoundFunction
public Varargs exp(Varargs args) {
return valueOf(Math.exp(args.checkdouble(1)));
}
/**
* math.floor (x)
*
* Returns the largest integer smaller than or equal to x.
*/
@LuaBoundFunction
public Varargs floor(Varargs args) {
return valueOf(Math.floor(args.checkdouble(1)));
}
/**
* math.rad (x)
*
* Returns the angle x (given in degrees) in radians.
*/
@LuaBoundFunction
public Varargs rad(Varargs args) {
return valueOf(Math.toRadians(args.checkdouble(1)));
}
/**
* math.sin (x)
*
* Returns the sine of x (assumed to be in radians).
*/
@LuaBoundFunction
public Varargs sin(Varargs args) {
return valueOf(Math.sin(args.checkdouble(1)));
}
/**
* math.sqrt (x)
*
* Returns the square root of x. (You can also use the expression x^0.5 to compute this value.)
*/
@LuaBoundFunction
public Varargs sqrt(Varargs args) {
return valueOf(Math.sqrt(args.checkdouble(1)));
}
/**
* math.tan (x)
*
* Returns the tangent of x (assumed to be in radians).
*/
@LuaBoundFunction
public Varargs tan(Varargs args) {
return valueOf(Math.tan(args.checkdouble(1)));
}
/**
* math.asin (x)
*
* Returns the arc sine of x (in radians).
*/
@LuaBoundFunction
public Varargs asin(Varargs args) {
return valueOf(Math.asin(args.checkdouble(1)));
}
/**
* math.acos (x)
*
* Returns the arc cosine of x (in radians).
*/
@LuaBoundFunction
public Varargs acos(Varargs args) {
return valueOf(Math.acos(args.checkdouble(1)));
}
/**
* math.atan (x)
*
* Returns the arc tangent of x (in radians).
*/
@LuaBoundFunction
public Varargs atan(Varargs args) {
return valueOf(Math.atan(args.checkdouble(1)));
}
/**
* math.atan2 (x)
*
* Returns the arc tangent of y/x (in radians), but uses the signs of both parameters to find the quadrant
* of the result. (It also handles correctly the case of x being zero.)
*/
@LuaBoundFunction
public Varargs atan2(Varargs args) {
return valueOf(Math.atan2(args.checkdouble(1), args.checkdouble(2)));
}
/**
* math.pow (x)
*
* Returns {@code xy }. (You can also use the expression {@code x^y} to compute this value.)
*/
@LuaBoundFunction
public Varargs pow(Varargs args) {
return args.arg(1).pow(args.checkdouble(2));
}
/**
* math.sinh (x)
*
* Returns the hyperbolic sine of x.
*/
@LuaBoundFunction
public Varargs sinh(Varargs args) {
return valueOf(Math.sinh(args.checkdouble(1)));
}
/**
* math.cosh (x)
*
* Returns the hyperbolic cosine of x.
*/
@LuaBoundFunction
public Varargs cosh(Varargs args) {
return valueOf(Math.cosh(args.checkdouble(1)));
}
/**
* math.tanh (x)
*
* Returns the hyperbolic tangent of x.
*/
@LuaBoundFunction
public Varargs tanh(Varargs args) {
return valueOf(Math.tanh(args.checkdouble(1)));
}
/**
* math.log (x)
*
* Returns the natural logarithm of x.
*/
@LuaBoundFunction
public Varargs log(Varargs args) {
return valueOf(Math.log(args.checkdouble(1)));
}
/**
* math.log10 (x)
*
* Returns the base-10 logarithm of x.
*/
@LuaBoundFunction
public Varargs log10(Varargs args) {
return valueOf(Math.log10(args.checkdouble(1)));
}
/**
* math.max (x, ...)
*
* Returns the maximum value among its arguments.
*/
@LuaBoundFunction
public Varargs max(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);
}
/**
* math.min (x, ...)
*
* Returns the minimum value among its arguments.
*/
@LuaBoundFunction
public Varargs min(Varargs args) {
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);
}
/**
* math.fmod (x)
*
* Returns the remainder of the division of x by y that rounds the quotient towards zero.
*/
@LuaBoundFunction
public Varargs fmod(Varargs args) {
double x = args.checkdouble(1);
double y = args.checkdouble(2);
double q = x / y;
double f = x - y * (q >= 0 ? Math.floor(q) : Math.ceil(q));
return valueOf(f);
}
/**
* math.ldexp (m, e)
*
* Returns m2e (e should be an integer).
*/
@LuaBoundFunction
public Varargs ldexp(Varargs args) {
double x = args.checkdouble(1);
double y = args.checkdouble(2) + 1023.5;
long e = (long)((0 != (1 & ((int)y))) ? Math.floor(y) : Math.ceil(y - 1));
return valueOf(x * Double.longBitsToDouble(e << 52));
}
/**
* math.frexp (x)
*
* Returns m and e such that x = m2e, e is an integer and the absolute value of m is in the
* range [0.5, 1) (or zero when x is zero).
*/
@LuaBoundFunction
public Varargs frexp(Varargs args) {
double x = args.checkdouble(1);
if (x == 0) {
return varargsOf(LuaInteger.valueOf(0), LuaInteger.valueOf(0));
}
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));
}
/**
* @deprecated Use {@link #fmod(Varargs)} instead.
*/
@Deprecated
@LuaBoundFunction
public Varargs mod(Varargs args) {
return fmod(args);
}
/**
* math.modf (x)
*
* Returns two numbers, the integral part of x and the fractional part of x.
*/
@LuaBoundFunction
public Varargs modf(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));
}
/**
* math.randomseed (x)
*
* Sets x as the "seed" for the pseudo-random generator: equal seeds produce equal sequences of numbers.
*/
@LuaBoundFunction
public Varargs randomseed(Varargs args) {
long seed = args.checklong(1);
random.setSeed(seed);
return NONE;
}
/**
* math.random ([m [, n]])
*
* This function is an interface to the simple pseudo-random generator function rand provided by Java.
* (No guarantees can be given for its statistical properties.)
*
* When called without arguments, returns a uniform pseudo-random real number in the range [0,1). When
* called with an integer number m, math.random returns a uniform pseudo-random integer in the range [1,
* m]. When called with two integer numbers m and n, math.random returns a uniform pseudo-random integer
* in the range [m, n].
*/
@LuaBoundFunction
public Varargs random(Varargs args) {
switch (args.narg()) {
case 0:
return valueOf(random.nextDouble());
case 1: {
int m = args.checkint(1);
if (m < 1) {
argerror(1, "interval is empty");
}
return valueOf(1 + 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 + random.nextInt(n + 1 - m));
}
}
}
}