commonMain.org.luaj.vm2.LuaDouble.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of luak Show documentation
Show all versions of luak Show documentation
Multiplatform Kotlin LuaJ port (LUA interpreter)
/*******************************************************************************
* Copyright (c) 2009-2011 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
import org.luaj.vm2.lib.MathLib
import kotlin.jvm.*
import kotlin.math.floor
/**
* Extension of [LuaNumber] which can hold a Java double as its value.
*
*
* These instance are not instantiated directly by clients, but indirectly
* via the static functions [LuaValue.valueOf] or [LuaValue.valueOf]
* functions. This ensures that values which can be represented as int
* are wrapped in [LuaInteger] instead of [LuaDouble].
*
*
* Almost all API's implemented in LuaDouble are defined and documented in [LuaValue].
*
*
* However the constants [.NAN], [.POSINF], [.NEGINF],
* [.JSTR_NAN], [.JSTR_POSINF], and [.JSTR_NEGINF] may be useful
* when dealing with Nan or Infinite values.
*
*
* LuaDouble also defines functions for handling the unique math rules of lua devision and modulo in
*
* * [.ddiv]
* * [.ddiv_d]
* * [.dmod]
* * [.dmod_d]
*
*
*
* @see LuaValue
*
* @see LuaNumber
*
* @see LuaInteger
*
* @see LuaValue.valueOf
* @see LuaValue.valueOf
*/
class LuaDouble
/** Don't allow ints to be boxed by DoubleValues */
private constructor(
/** The value being held by this instance. */
internal val v: Double
) : LuaNumber() {
override fun hashCode(): Int = (v + 1).toRawBits().let { l -> (l shr 32).toInt() + l.toInt() }
override fun islong(): Boolean = v == v.toLong().toDouble()
override fun tobyte(): Byte = v.toLong().toByte()
override fun tochar(): Char = v.toLong().toChar()
override fun todouble(): Double = v
override fun tofloat(): Float = v.toFloat()
override fun toint(): Int = v.toLong().toInt()
override fun tolong(): Long = v.toLong()
override fun toshort(): Short = v.toLong().toShort()
override fun optdouble(defval: Double): Double = v
override fun optint(defval: Int): Int = v.toLong().toInt()
override fun optinteger(defval: LuaInteger?): LuaInteger? = LuaInteger.valueOf(v.toLong().toInt())
override fun optlong(defval: Long): Long = v.toLong()
override fun checkinteger(): LuaInteger? = LuaInteger.valueOf(v.toLong().toInt())
// unary operators
override fun neg(): LuaValue = valueOf(-v)
// object equality, used for key comparison
override fun equals(o: Any?): Boolean = if (o is LuaDouble) o.v == v else false
// equality w/ metatable processing
override fun eq(`val`: LuaValue): LuaValue = if (`val`.raweq(v)) LuaValue.TRUE else LuaValue.FALSE
override fun eq_b(`val`: LuaValue): Boolean = `val`.raweq(v)
// equality w/o metatable processing
override fun raweq(`val`: LuaValue): Boolean = `val`.raweq(v)
override fun raweq(`val`: Double): Boolean = v == `val`
override fun raweq(`val`: Int): Boolean = v == `val`.toDouble()
// basic binary arithmetic
override fun add(rhs: LuaValue): LuaValue = rhs.add(v)
override fun add(lhs: Double): LuaValue = LuaDouble.valueOf(lhs + v)
override fun sub(rhs: LuaValue): LuaValue = rhs.subFrom(v)
override fun sub(rhs: Double): LuaValue = LuaDouble.valueOf(v - rhs)
override fun sub(rhs: Int): LuaValue = LuaDouble.valueOf(v - rhs)
override fun subFrom(lhs: Double): LuaValue = LuaDouble.valueOf(lhs - v)
override fun mul(rhs: LuaValue): LuaValue = rhs.mul(v)
override fun mul(lhs: Double): LuaValue = LuaDouble.valueOf(lhs * v)
override fun mul(lhs: Int): LuaValue = LuaDouble.valueOf(lhs * v)
override fun pow(rhs: LuaValue): LuaValue = rhs.powWith(v)
override fun pow(rhs: Double): LuaValue = MathLib.dpow(v, rhs)
override fun pow(rhs: Int): LuaValue = MathLib.dpow(v, rhs.toDouble())
override fun powWith(lhs: Double): LuaValue = MathLib.dpow(lhs, v)
override fun powWith(lhs: Int): LuaValue = MathLib.dpow(lhs.toDouble(), v)
override fun div(rhs: LuaValue): LuaValue = rhs.divInto(v)
override fun div(rhs: Double): LuaValue = LuaDouble.ddiv(v, rhs)
override fun div(rhs: Int): LuaValue = LuaDouble.ddiv(v, rhs.toDouble())
override fun divInto(lhs: Double): LuaValue = LuaDouble.ddiv(lhs, v)
override fun mod(rhs: LuaValue): LuaValue = rhs.modFrom(v)
override fun mod(rhs: Double): LuaValue = LuaDouble.dmod(v, rhs)
override fun mod(rhs: Int): LuaValue = LuaDouble.dmod(v, rhs.toDouble())
override fun modFrom(lhs: Double): LuaValue = LuaDouble.dmod(lhs, v)
// relational operators
override fun lt(rhs: LuaValue): LuaValue = if (rhs.gt_b(v)) LuaValue.TRUE else LuaValue.FALSE
override fun lt(rhs: Double): LuaValue = if (v < rhs) LuaValue.TRUE else LuaValue.FALSE
override fun lt(rhs: Int): LuaValue = if (v < rhs) LuaValue.TRUE else LuaValue.FALSE
override fun lt_b(rhs: LuaValue): Boolean = rhs.gt_b(v)
override fun lt_b(rhs: Int): Boolean = v < rhs
override fun lt_b(rhs: Double): Boolean = v < rhs
override fun lteq(rhs: LuaValue): LuaValue = if (rhs.gteq_b(v)) LuaValue.TRUE else LuaValue.FALSE
override fun lteq(rhs: Double): LuaValue = if (v <= rhs) LuaValue.TRUE else LuaValue.FALSE
override fun lteq(rhs: Int): LuaValue = if (v <= rhs) LuaValue.TRUE else LuaValue.FALSE
override fun lteq_b(rhs: LuaValue): Boolean = rhs.gteq_b(v)
override fun lteq_b(rhs: Int): Boolean = v <= rhs
override fun lteq_b(rhs: Double): Boolean = v <= rhs
override fun gt(rhs: LuaValue): LuaValue = if (rhs.lt_b(v)) LuaValue.TRUE else LuaValue.FALSE
override fun gt(rhs: Double): LuaValue = if (v > rhs) LuaValue.TRUE else LuaValue.FALSE
override fun gt(rhs: Int): LuaValue = if (v > rhs) LuaValue.TRUE else LuaValue.FALSE
override fun gt_b(rhs: LuaValue): Boolean = rhs.lt_b(v)
override fun gt_b(rhs: Int): Boolean = v > rhs
override fun gt_b(rhs: Double): Boolean = v > rhs
override fun gteq(rhs: LuaValue): LuaValue = if (rhs.lteq_b(v)) LuaValue.TRUE else LuaValue.FALSE
override fun gteq(rhs: Double): LuaValue = if (v >= rhs) LuaValue.TRUE else LuaValue.FALSE
override fun gteq(rhs: Int): LuaValue = if (v >= rhs) LuaValue.TRUE else LuaValue.FALSE
override fun gteq_b(rhs: LuaValue): Boolean = rhs.lteq_b(v)
override fun gteq_b(rhs: Int): Boolean = v >= rhs
override fun gteq_b(rhs: Double): Boolean = v >= rhs
// string comparison
override fun strcmp(rhs: LuaString): Int = typerror("attempt to compare number with string")
override fun tojstring(): String {
val l = v.toLong()
return when {
l.toDouble() == v -> l.toString()
v.isNaN() -> JSTR_NAN
else -> if ((v).isInfinite()) if (v < 0) JSTR_NEGINF else JSTR_POSINF else v.toFloat().toString()
}
}
override fun strvalue(): LuaString? = LuaString.valueOf(tojstring())
override fun optstring(defval: LuaString?): LuaString? = LuaString.valueOf(tojstring())
override fun tostring(): LuaValue = LuaString.valueOf(tojstring())
override fun optjstring(defval: String?): String? = tojstring()
override fun optnumber(defval: LuaNumber?): LuaNumber? = this
override fun isnumber(): Boolean = true
override fun isstring(): Boolean = true
override fun tonumber(): LuaValue = this
override fun checkint(): Int = v.toLong().toInt()
override fun checklong(): Long = v.toLong()
override fun checknumber(): LuaNumber? = this
override fun checkdouble(): Double = v
override fun checkjstring(): String? = tojstring()
override fun checkstring(): LuaString = LuaString.valueOf(tojstring())
override fun isvalidkey(): Boolean = !(v.isNaN())
companion object {
/** Constant LuaDouble representing NaN (not a number) */
@kotlin.jvm.JvmField val NAN = LuaDouble(Double.NaN)
/** Constant LuaDouble representing positive infinity */
@kotlin.jvm.JvmField val POSINF = LuaDouble(Double.POSITIVE_INFINITY)
/** Constant LuaDouble representing negative infinity */
@kotlin.jvm.JvmField val NEGINF = LuaDouble(Double.NEGATIVE_INFINITY)
/** Constant String representation for NaN (not a number), "nan" */
@kotlin.jvm.JvmField val JSTR_NAN = "nan"
/** Constant String representation for positive infinity, "inf" */
@kotlin.jvm.JvmField val JSTR_POSINF = "inf"
/** Constant String representation for negative infinity, "-inf" */
@kotlin.jvm.JvmField val JSTR_NEGINF = "-inf"
@JvmName("valueOf2")
fun valueOf(d: Double): LuaNumber =
d.toInt().let { id -> if (d == id.toDouble()) LuaInteger.valueOf(id) else LuaDouble(d) }
/** Divide two double numbers according to lua math, and return a [LuaValue] result.
* @param lhs Left-hand-side of the division.
* @param rhs Right-hand-side of the division.
* @return [LuaValue] for the result of the division,
* taking into account positive and negiative infinity, and Nan
* @see .ddiv_d
*/
fun ddiv(lhs: Double, rhs: Double): LuaValue =
if (rhs != 0.0) valueOf(lhs / rhs) else if (lhs > 0) POSINF else if (lhs == 0.0) NAN else NEGINF
/** Divide two double numbers according to lua math, and return a double result.
* @param lhs Left-hand-side of the division.
* @param rhs Right-hand-side of the division.
* @return Value of the division, taking into account positive and negative infinity, and Nan
* @see .ddiv
*/
fun ddiv_d(lhs: Double, rhs: Double): Double = when {
rhs != 0.0 -> lhs / rhs
lhs > 0 -> Double.POSITIVE_INFINITY
lhs == 0.0 -> Double.NaN
else -> Double.NEGATIVE_INFINITY
}
/** Take modulo double numbers according to lua math, and return a [LuaValue] result.
* @param lhs Left-hand-side of the modulo.
* @param rhs Right-hand-side of the modulo.
* @return [LuaValue] for the result of the modulo,
* using lua's rules for modulo
* @see .dmod_d
*/
fun dmod(lhs: Double, rhs: Double): LuaValue =
if (rhs != 0.0) valueOf(lhs - rhs * kotlin.math.floor(lhs / rhs)) else NAN
/** Take modulo for double numbers according to lua math, and return a double result.
* @param lhs Left-hand-side of the modulo.
* @param rhs Right-hand-side of the modulo.
* @return double value for the result of the modulo,
* using lua's rules for modulo
* @see .dmod
*/
fun dmod_d(lhs: Double, rhs: Double): Double = when {
rhs != 0.0 -> lhs - rhs * kotlin.math.floor(lhs / rhs)
else -> Double.NaN
}
}
}