Lua math library
parent
b398a6b2ff
commit
66433d27cc
|
@ -29,6 +29,10 @@ Deno.test("[Lua] OS tests", async () => {
|
|||
await runLuaTest("./stdlib/os_test.lua");
|
||||
});
|
||||
|
||||
Deno.test("[Lua] Math tests", async () => {
|
||||
await runLuaTest("./stdlib/math_test.lua");
|
||||
});
|
||||
|
||||
Deno.test("[Lua] JS tests", async () => {
|
||||
await runLuaTest("./stdlib/js_test.lua");
|
||||
});
|
||||
|
|
|
@ -27,6 +27,7 @@ import {
|
|||
type LuaQueryCollection,
|
||||
} from "$common/space_lua/query_collection.ts";
|
||||
import { templateApi } from "$common/space_lua/stdlib/template.ts";
|
||||
import { mathApi } from "$common/space_lua/stdlib/math.ts";
|
||||
|
||||
const printFunction = new LuaBuiltinFunction(async (_sf, ...args) => {
|
||||
console.log("[Lua]", ...(await Promise.all(args.map(luaToString))));
|
||||
|
@ -235,6 +236,7 @@ export function luaBuildStandardEnv() {
|
|||
env.set("table", tableApi);
|
||||
env.set("os", osApi);
|
||||
env.set("js", jsApi);
|
||||
env.set("math", mathApi);
|
||||
// Non-standard
|
||||
env.set("each", eachFunction);
|
||||
env.set("space_lua", spaceLuaApi);
|
||||
|
|
|
@ -0,0 +1,221 @@
|
|||
API docs for Lua's `math` module.
|
||||
|
||||
## math.random(m?, n?)
|
||||
Generates random numbers. Without arguments, returns a float in [0,1). With one argument m, returns integer in [1,m]. With two arguments, returns integer in [m,n].
|
||||
|
||||
Example:
|
||||
```lua
|
||||
print(math.random()) -- prints: 0.7259081864761557
|
||||
print(math.random(10)) -- prints: 7 (random number from 1-10)
|
||||
print(math.random(5,10)) -- prints: 8 (random number from 5-10)
|
||||
```
|
||||
|
||||
## math.abs(x)
|
||||
Returns the absolute value of `x`.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
print(math.abs(-5)) -- prints: 5
|
||||
print(math.abs(3.7)) -- prints: 3.7
|
||||
```
|
||||
|
||||
## math.ceil(x)
|
||||
Returns the smallest integer larger than or equal to `x`.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
print(math.ceil(3.3)) -- prints: 4
|
||||
print(math.ceil(-3.3)) -- prints: -3
|
||||
```
|
||||
|
||||
## math.floor(x)
|
||||
Returns the largest integer smaller than or equal to `x`.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
print(math.floor(3.7)) -- prints: 3
|
||||
print(math.floor(-3.7)) -- prints: -4
|
||||
```
|
||||
|
||||
## math.max(...)
|
||||
Returns the maximum value among its arguments.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
print(math.max(1, 2, 3, 4)) -- prints: 4
|
||||
print(math.max(-5, -2, -10)) -- prints: -2
|
||||
```
|
||||
|
||||
## math.min(...)
|
||||
Returns the minimum value among its arguments.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
print(math.min(1, 2, 3, 4)) -- prints: 1
|
||||
print(math.min(-5, -2, -10)) -- prints: -10
|
||||
```
|
||||
|
||||
## math.fmod(x, y)
|
||||
Returns the remainder of the division of `x` by `y`.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
print(math.fmod(7, 3)) -- prints: 1
|
||||
print(math.fmod(7, 2)) -- prints: 1
|
||||
```
|
||||
|
||||
## math.modf(x)
|
||||
Returns the integral part and fractional part of `x`.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
local int, frac = table.unpack(math.modf(3.7))
|
||||
print(int, frac) -- prints: 3 0.7
|
||||
```
|
||||
|
||||
## math.exp(x)
|
||||
Returns e raised to the power of `x`.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
print(math.exp(0)) -- prints: 1
|
||||
print(math.exp(1)) -- prints: 2.718281828459045
|
||||
```
|
||||
|
||||
## math.log(x, base?)
|
||||
Returns the natural logarithm of `x` or the logarithm of `x` to the given base.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
print(math.log(math.exp(1))) -- prints: 1
|
||||
print(math.log(8, 2)) -- prints: 3
|
||||
```
|
||||
|
||||
## math.pow(x, y)
|
||||
Returns `x` raised to the power `y`.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
print(math.pow(2, 3)) -- prints: 8
|
||||
print(math.pow(3, 2)) -- prints: 9
|
||||
```
|
||||
|
||||
## math.sqrt(x)
|
||||
Returns the square root of `x`.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
print(math.sqrt(9)) -- prints: 3
|
||||
print(math.sqrt(2)) -- prints: 1.4142135623730951
|
||||
```
|
||||
|
||||
## math.cos(x)
|
||||
Returns the cosine of `x` (in radians).
|
||||
|
||||
Example:
|
||||
```lua
|
||||
print(math.cos(0)) -- prints: 1
|
||||
```
|
||||
|
||||
## math.sin(x)
|
||||
Returns the sine of `x` (in radians).
|
||||
|
||||
Example:
|
||||
```lua
|
||||
print(math.sin(0)) -- prints: 0
|
||||
```
|
||||
|
||||
## math.tan(x)
|
||||
Returns the tangent of `x` (in radians).
|
||||
|
||||
Example:
|
||||
```lua
|
||||
print(math.tan(0)) -- prints: 0
|
||||
```
|
||||
|
||||
## math.acos(x)
|
||||
Returns the arc cosine of `x` (in radians).
|
||||
|
||||
Example:
|
||||
```lua
|
||||
print(math.acos(1)) -- prints: 0
|
||||
print(math.acos(0)) -- prints: 1.5707963267948966
|
||||
```
|
||||
|
||||
## math.asin(x)
|
||||
Returns the arc sine of `x` (in radians).
|
||||
|
||||
Example:
|
||||
```lua
|
||||
print(math.asin(0)) -- prints: 0
|
||||
print(math.asin(1)) -- prints: 1.5707963267948966
|
||||
```
|
||||
|
||||
## math.atan(y, x?)
|
||||
Returns the arc tangent of `y/x` (in radians). If `x` is not provided, returns the arc tangent of `y`.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
print(math.atan(0)) -- prints: 0
|
||||
print(math.atan(1, 1)) -- prints: 0.7853981633974483
|
||||
```
|
||||
|
||||
## math.cosh(x)
|
||||
Returns the hyperbolic cosine of `x`.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
print(math.cosh(0)) -- prints: 1
|
||||
print(math.cosh(1)) -- prints: 1.5430806348152437
|
||||
```
|
||||
|
||||
## math.sinh(x)
|
||||
Returns the hyperbolic sine of `x`.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
print(math.sinh(0)) -- prints: 0
|
||||
print(math.sinh(1)) -- prints: 1.1752011936438014
|
||||
```
|
||||
|
||||
## math.tanh(x)
|
||||
Returns the hyperbolic tangent of `x`.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
print(math.tanh(0)) -- prints: 0
|
||||
print(math.tanh(1)) -- prints: 0.7615941559557649
|
||||
```
|
||||
|
||||
## math.deg(x)
|
||||
Converts angle `x` from radians to degrees.
|
||||
|
||||
|
||||
## math.rad(x)
|
||||
Converts angle `x` from degrees to radians.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
print(math.rad(180)) -- prints: 3.141592653589793
|
||||
print(math.rad(90)) -- prints: 1.5707963267948966
|
||||
```
|
||||
|
||||
## math.ult(m, n)
|
||||
Returns true if `m` is less than `n` when they are considered unsigned integers.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
print(math.ult(1, 2)) -- prints: true
|
||||
print(math.ult(2, 1)) -- prints: false
|
||||
```
|
||||
|
||||
# Non-standard Extensions
|
||||
## math.cosine_similarity(vecA, vecB)
|
||||
Returns the cosine similarity between two vectors.
|
||||
|
||||
Example:
|
||||
```lua
|
||||
local vec1 = {1, 2, 3}
|
||||
local vec2 = {4, 5, 6}
|
||||
print(math.cosine_similarity(vec1, vec2)) -- prints: 0.9746318461970762
|
||||
```
|
|
@ -0,0 +1,94 @@
|
|||
import {
|
||||
LuaBuiltinFunction,
|
||||
LuaRuntimeError,
|
||||
LuaTable,
|
||||
} from "$common/space_lua/runtime.ts";
|
||||
|
||||
export const mathApi = new LuaTable({
|
||||
// Random number generation
|
||||
random: new LuaBuiltinFunction((_sf, m?: number, n?: number) => {
|
||||
if (m === undefined && n === undefined) {
|
||||
// random() returns [0,1)
|
||||
return Math.random();
|
||||
} else if (n === undefined) {
|
||||
// random(m) returns [1,m]
|
||||
return Math.floor(Math.random() * m!) + 1;
|
||||
} else {
|
||||
// random(m,n) returns [m,n]
|
||||
return Math.floor(Math.random() * (n - m! + 1)) + m!;
|
||||
}
|
||||
}),
|
||||
|
||||
// Basic functions
|
||||
abs: new LuaBuiltinFunction((_sf, x: number) => Math.abs(x)),
|
||||
ceil: new LuaBuiltinFunction((_sf, x: number) => Math.ceil(x)),
|
||||
floor: new LuaBuiltinFunction((_sf, x: number) => Math.floor(x)),
|
||||
max: new LuaBuiltinFunction((_sf, ...args: number[]) => Math.max(...args)),
|
||||
min: new LuaBuiltinFunction((_sf, ...args: number[]) => Math.min(...args)),
|
||||
|
||||
// Rounding and remainder
|
||||
fmod: new LuaBuiltinFunction((_sf, x: number, y: number) => x % y),
|
||||
modf: new LuaBuiltinFunction((_sf, x: number) => {
|
||||
const int = Math.floor(x);
|
||||
const frac = x - int;
|
||||
return new LuaTable([int, frac]);
|
||||
}),
|
||||
|
||||
// Power and logarithms
|
||||
exp: new LuaBuiltinFunction((_sf, x: number) => Math.exp(x)),
|
||||
log: new LuaBuiltinFunction((_sf, x: number, base?: number) => {
|
||||
if (base === undefined) {
|
||||
return Math.log(x);
|
||||
}
|
||||
return Math.log(x) / Math.log(base);
|
||||
}),
|
||||
pow: new LuaBuiltinFunction((_sf, x: number, y: number) => Math.pow(x, y)),
|
||||
sqrt: new LuaBuiltinFunction((_sf, x: number) => Math.sqrt(x)),
|
||||
|
||||
// Trigonometric functions
|
||||
cos: new LuaBuiltinFunction((_sf, x: number) => Math.cos(x)),
|
||||
sin: new LuaBuiltinFunction((_sf, x: number) => Math.sin(x)),
|
||||
tan: new LuaBuiltinFunction((_sf, x: number) => Math.tan(x)),
|
||||
acos: new LuaBuiltinFunction((_sf, x: number) => Math.acos(x)),
|
||||
asin: new LuaBuiltinFunction((_sf, x: number) => Math.asin(x)),
|
||||
atan: new LuaBuiltinFunction((_sf, y: number, x?: number) => {
|
||||
if (x === undefined) {
|
||||
return Math.atan(y);
|
||||
}
|
||||
return Math.atan2(y, x);
|
||||
}),
|
||||
|
||||
// Hyperbolic functions
|
||||
cosh: new LuaBuiltinFunction((_sf, x: number) => Math.cosh(x)),
|
||||
sinh: new LuaBuiltinFunction((_sf, x: number) => Math.sinh(x)),
|
||||
tanh: new LuaBuiltinFunction((_sf, x: number) => Math.tanh(x)),
|
||||
|
||||
// Additional utility
|
||||
deg: new LuaBuiltinFunction((_sf, x: number) => x * 180 / Math.PI),
|
||||
rad: new LuaBuiltinFunction((_sf, x: number) => x * Math.PI / 180),
|
||||
ult: new LuaBuiltinFunction((_sf, m: number, n: number) => {
|
||||
// Unsigned less than comparison
|
||||
return (m >>> 0) < (n >>> 0);
|
||||
}),
|
||||
|
||||
// Keep the cosine_similarity utility function
|
||||
cosine_similarity: new LuaBuiltinFunction(
|
||||
(sf, vecA: number[], vecB: number[]) => {
|
||||
if (vecA.length !== vecB.length) {
|
||||
throw new LuaRuntimeError("Vectors must be of the same length", sf);
|
||||
}
|
||||
|
||||
let dotProduct = 0;
|
||||
let normA = 0;
|
||||
let normB = 0;
|
||||
|
||||
for (let i = 0; i < vecA.length; i++) {
|
||||
dotProduct += vecA[i] * vecB[i];
|
||||
normA += vecA[i] ** 2;
|
||||
normB += vecB[i] ** 2;
|
||||
}
|
||||
|
||||
return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
|
||||
},
|
||||
),
|
||||
});
|
|
@ -0,0 +1,48 @@
|
|||
local function assert_equal(a, b)
|
||||
if a ~= b then
|
||||
error("Assertion failed: " .. a .. " is not equal to " .. b)
|
||||
end
|
||||
end
|
||||
|
||||
-- Trigonometric functions
|
||||
assert_equal(math.cos(0), 1)
|
||||
assert_equal(math.sin(0), 0)
|
||||
assert_equal(math.tan(0), 0)
|
||||
assert_equal(math.acos(1), 0)
|
||||
assert_equal(math.asin(0), 0)
|
||||
assert_equal(math.atan(0), 0)
|
||||
|
||||
-- Hyperbolic functions
|
||||
assert_equal(math.cosh(0), 1)
|
||||
assert_equal(math.sinh(0), 0)
|
||||
assert_equal(math.tanh(0), 0)
|
||||
|
||||
-- Basic functions
|
||||
assert_equal(math.abs(-5), 5)
|
||||
assert_equal(math.ceil(3.3), 4)
|
||||
assert_equal(math.floor(3.7), 3)
|
||||
assert_equal(math.max(1, 2, 3, 4), 4)
|
||||
assert_equal(math.min(1, 2, 3, 4), 1)
|
||||
|
||||
-- Rounding and remainder
|
||||
assert_equal(math.fmod(7, 3), 1)
|
||||
|
||||
-- Power and logarithms
|
||||
assert_equal(math.exp(0), 1)
|
||||
assert_equal(math.log(math.exp(1)), 1)
|
||||
assert_equal(math.log(8, 2), 3) -- log base 2 of 8
|
||||
assert_equal(math.pow(2, 3), 8)
|
||||
assert_equal(math.sqrt(9), 3)
|
||||
|
||||
|
||||
-- Random number tests (basic range checks)
|
||||
local rand = math.random()
|
||||
assert_equal(rand >= 0 and rand < 1, true)
|
||||
local rand_n = math.random(10)
|
||||
assert_equal(rand_n >= 1 and rand_n <= 10, true)
|
||||
local rand_range = math.random(5, 10)
|
||||
assert_equal(rand_range >= 5 and rand_range <= 10, true)
|
||||
|
||||
-- Unsigned less than comparison
|
||||
assert_equal(math.ult(1, 2), true)
|
||||
assert_equal(math.ult(2, 1), false)
|
Loading…
Reference in New Issue