All Downloads are FREE. Search and download functionalities are using the official Maven repository.

commonMain.org.luaj.vm2.lib.MathLib.kt Maven / Gradle / Ivy

/*******************************************************************************
 * Copyright (c) 2009 Luaj.org. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package org.luaj.vm2.lib

import org.luaj.vm2.LuaDouble
import org.luaj.vm2.LuaTable
import org.luaj.vm2.LuaValue
import org.luaj.vm2.Varargs
import org.luaj.vm2.internal.*
import kotlin.math.*
import kotlin.native.concurrent.*
import kotlin.random.Random

/**
 * Subclass of [LibFunction] which implements the lua standard `math`
 * library.
 *
 *
 * It contains only the math library support that is possible on JME.
 * For a more complete implementation based on math functions specific to JSE
 * use [org.luaj.vm2.lib.jse.JseMathLib].
 * In Particular the following math functions are **not** implemented by this library:
 *
 *  * acos
 *  * asin
 *  * atan
 *  * cosh
 *  * log
 *  * sinh
 *  * tanh
 *  * atan2
 *
 *
 *
 * The implementations of `exp()` and `pow()` are constructed by
 * hand for JME, so will be slower and less accurate than when executed on the JSE platform.
 *
 *
 * Typically, this library is included as part of a call to either
 * [org.luaj.vm2.lib.jse.JsePlatform.standardGlobals] or
 * [org.luaj.vm2.lib.jme.JmePlatform.standardGlobals]
 * 
 `Globals globals = JsePlatform.standardGlobals();
 * System.out.println( globals.get("math").get("sqrt").call( LuaValue.valueOf(2) ) );
` *  
* When using [org.luaj.vm2.lib.jse.JsePlatform] as in this example, * the subclass [org.luaj.vm2.lib.jse.JseMathLib] will * be included, which also includes this base functionality. * * * To instantiate and use it directly, * link it into your globals table via [LuaValue.load] using code such as: *
 `Globals globals = new Globals();
 * globals.load(new JseBaseLib());
 * globals.load(new PackageLib());
 * globals.load(new MathLib());
 * System.out.println( globals.get("math").get("sqrt").call( LuaValue.valueOf(2) ) );
` *  
* Doing so will ensure the library is properly initialized * and loaded into the globals table. * * * This has been implemented to match as closely as possible the behavior in the corresponding library in C. * @see LibFunction * * @see org.luaj.vm2.lib.jse.JsePlatform * * @see org.luaj.vm2.lib.jme.JmePlatform * * @see org.luaj.vm2.lib.jse.JseMathLib * * @see [Lua 5.2 Math Lib Reference](http://www.lua.org/manual/5.2/manual.html.6.6) */ open class MathLib : TwoArgFunction() { /** Construct a MathLib, which can be initialized by calling it with a * modname string, and a global environment table as arguments using * [.call]. */ init { MATHLIB = this } /** Perform one-time initialization on the library by creating a table * containing the library functions, adding that table to the supplied environment, * adding the table to package.loaded, and returning table as the return value. * @param modname the module name supplied if this is loaded via 'require'. * @param env the environment to load into, typically a Globals instance. */ override fun call(modname: LuaValue, env: LuaValue): LuaValue { val math = LuaTable(0, 30) math.set("abs", abs()) math.set("ceil", ceil()) math.set("cos", cos()) math.set("deg", deg()) math.set("exp", exp(this)) math.set("floor", floor()) math.set("fmod", fmod()) math.set("frexp", frexp()) math.set("huge", LuaDouble.POSINF) math.set("ldexp", ldexp()) math.set("max", max()) math.set("min", min()) math.set("modf", modf()) math.set("pi", kotlin.math.PI) math.set("pow", pow()) val r = random() math.set("random", r) math.set("randomseed", randomseed(r)) math.set("rad", rad()) math.set("sin", sin()) math.set("sqrt", sqrt()) math.set("tan", tan()) env.set("math", math) env.get("package").get("loaded").set("math", math) return math } abstract class UnaryOp : OneArgFunction() { override fun call(arg: LuaValue): LuaValue { return LuaValue.valueOf(call(arg.checkdouble())) } protected abstract fun call(d: Double): Double } abstract class BinaryOp : TwoArgFunction() { override fun call(x: LuaValue, y: LuaValue): LuaValue { return LuaValue.valueOf(call(x.checkdouble(), y.checkdouble())) } protected abstract fun call(x: Double, y: Double): Double } internal class abs : UnaryOp() { override fun call(d: Double): Double { return kotlin.math.abs(d) } } internal class ceil : UnaryOp() { override fun call(d: Double): Double { return kotlin.math.ceil(d) } } internal class cos : UnaryOp() { override fun call(d: Double): Double { return kotlin.math.cos(d) } } internal class deg : UnaryOp() { override fun call(d: Double): Double { return d * 180.0 / kotlin.math.PI } } internal class floor : UnaryOp() { override fun call(d: Double): Double { return kotlin.math.floor(d) } } internal class rad : UnaryOp() { override fun call(d: Double): Double { return d / 180.0 * kotlin.math.PI } } internal class sin : UnaryOp() { override fun call(d: Double): Double { return kotlin.math.sin(d) } } internal class sqrt : UnaryOp() { override fun call(d: Double): Double { return kotlin.math.sqrt(d) } } internal class tan : UnaryOp() { override fun call(d: Double): Double { return kotlin.math.tan(d) } } internal class exp(val mathlib: MathLib) : UnaryOp() { override fun call(d: Double): Double { return mathlib.dpow_lib(kotlin.math.E, d) } } internal class fmod : BinaryOp() { override fun call(x: Double, y: Double): Double { val q = x / y return x - y * if (q >= 0) kotlin.math.floor(q) else kotlin.math.ceil(q) } } internal class ldexp : BinaryOp() { override fun call(x: Double, y: Double): Double { // This is the behavior on os-x, windows differs in rounding behavior. return x * Double.fromBits(y.toLong() + 1023 shl 52) } } internal class pow : BinaryOp() { override fun call(x: Double, y: Double): Double { return MathLib.dpow_default(x, y) } } internal class frexp : VarArgFunction() { override fun invoke(args: Varargs): Varargs { val x = args.checkdouble(1) if (x == 0.0) return LuaValue.varargsOf(LuaValue.ZERO, LuaValue.ZERO) val bits = (x).toRawBits() val m = ((bits and (-1L shl 52).inv()) + (1L shl 52)) * if (bits >= 0) .5 / (1L shl 52) else -.5 / (1L shl 52) val e = (((bits shr 52).toInt() and 0x7ff) - 1022).toDouble() return LuaValue.varargsOf(LuaValue.valueOf(m), LuaValue.valueOf(e)) } } internal class max : VarArgFunction() { override fun invoke(args: Varargs): Varargs { var m = args.checkdouble(1) var i = 2 val n = args.narg() while (i <= n) { m = max(m, args.checkdouble(i)) ++i } return LuaValue.valueOf(m) } } internal class min : VarArgFunction() { override fun invoke(args: Varargs): Varargs { var m = args.checkdouble(1) var i = 2 val n = args.narg() while (i <= n) { m = min(m, args.checkdouble(i)) ++i } return LuaValue.valueOf(m) } } internal class modf : VarArgFunction() { override fun invoke(args: Varargs): Varargs { val x = args.checkdouble(1) val intPart = if (x > 0) kotlin.math.floor(x) else kotlin.math.ceil(x) val fracPart = x - intPart return LuaValue.varargsOf(LuaValue.valueOf(intPart), LuaValue.valueOf(fracPart)) } } internal class random : LibFunction() { var random: Random = Random.Default override fun call(): LuaValue { return LuaValue.valueOf(random.nextDouble()) } override fun call(a: LuaValue): LuaValue { val m = a.checkint() if (m < 1) LuaValue.argerror(1, "interval is empty") return LuaValue.valueOf(1 + random.nextInt(m)) } override fun call(a: LuaValue, b: LuaValue): LuaValue { val m = a.checkint() val n = b.checkint() if (n < m) LuaValue.argerror(2, "interval is empty") return LuaValue.valueOf(m + random.nextInt(n + 1 - m)) } } internal class randomseed(val random: random) : OneArgFunction() { override fun call(arg: LuaValue): LuaValue { val seed = arg.checklong() random.random = Random(seed) return LuaValue.NONE } } /** * Hook to override default dpow behavior with faster implementation. */ open fun dpow_lib(a: Double, b: Double): Double { return dpow_default(a, b) } companion object { /** Pointer to the latest MathLib instance, used only to dispatch * math.exp to tha correct platform math library. */ var MATHLIB: MathLib? get() = MathLib_MATHLIB set(value) { MathLib_MATHLIB = value } /** compute power using installed math library, or default if there is no math library installed */ fun dpow(a: Double, b: Double): LuaValue { return LuaDouble.valueOf( if (MATHLIB != null) MATHLIB!!.dpow_lib(a, b) else dpow_default(a, b) ) } fun dpow_d(a: Double, b: Double): Double { return if (MATHLIB != null) MATHLIB!!.dpow_lib(a, b) else dpow_default(a, b) } /** * Default JME version computes using longhand heuristics. */ protected fun dpow_default(a: Double, b: Double): Double { var a = a var b = b if (b < 0) return 1 / dpow_default(a, -b) var p = 1.0 var whole = b.toInt() var v = a while (whole > 0) { if (whole and 1 != 0) p *= v whole = whole shr 1 v *= v } if ((run { b -= whole.toDouble() b }) > 0) { var frac = (0x10000 * b).toInt() while (frac and 0xffff != 0) { a = kotlin.math.sqrt(a) if (frac and 0x8000 != 0) p *= a frac = frac shl 1 } } return p } } } @ThreadLocal private var MathLib_MATHLIB: MathLib? = null




© 2015 - 2024 Weber Informatics LLC | Privacy Policy