diff --git a/client/space_lua/stdlib/math.ts b/client/space_lua/stdlib/math.ts index f83c0d3e..ce659ebd 100644 --- a/client/space_lua/stdlib/math.ts +++ b/client/space_lua/stdlib/math.ts @@ -4,7 +4,7 @@ import { LuaRuntimeError, LuaTable, } from "../runtime.ts"; -import { isNegativeZero, isTaggedFloat } from "../numeric.ts"; +import { isNegativeZero, isTaggedFloat, makeLuaFloat } from "../numeric.ts"; // Fast unwrap: avoids function call overhead for the common plain-number case function untagNumber(x: any): number { @@ -117,7 +117,8 @@ export const mathApi = new LuaTable({ modf: new LuaBuiltinFunction((_sf, x: number) => { const xn = untagNumber(x); const int = Math.trunc(xn); - const frac = xn - int; + // Guarantee that the `frac` part is always Lua float + const frac = makeLuaFloat(xn - int); return new LuaMultiRes([int, frac]); }), diff --git a/client/space_lua/stdlib/math_test.lua b/client/space_lua/stdlib/math_test.lua index c6e4c7f7..921c0ac8 100644 --- a/client/space_lua/stdlib/math_test.lua +++ b/client/space_lua/stdlib/math_test.lua @@ -81,12 +81,22 @@ end -- modf do local i, f = math.modf(3.5) + assertEquals(math.type(i), "integer", "modf int part is integer") + assertEquals(math.type(f), "float", "modf frac part is float") assertEquals(i, 3, "modf(3.5) int") assertClose(f, 0.5, 1e-12, "modf(3.5) frac") local i2, f2 = math.modf(-3.5) + assertEquals(math.type(i2), "integer", "modf neg int part is integer") + assertEquals(math.type(f2), "float", "modf neg frac part is float") assertEquals(i2, -3, "modf(-3.5) int") assertClose(f2, -0.5, 1e-12, "modf(-3.5) frac") + + local i3, f3 = math.modf(4.0) + assertEquals(math.type(i3), "integer", "modf whole int part is integer") + assertEquals(math.type(f3), "float", "modf whole frac is float") + assertEquals(i3, 4, "modf(4.0) int") + assertEquals(f3, 0.0, "modf(4.0) frac") end -- sqrt/exp/log/pow