From 2b6894d81ef6ce7b389b1f0cd8c5305ceb3c9f71 Mon Sep 17 00:00:00 2001 From: He-Pin Date: Sat, 28 Feb 2026 15:31:24 +0800 Subject: [PATCH] chore: update stdlib_smoke_test.jsonnet with with float closing test --- testdata/stdlib_smoke_test.golden | 16 +++++------ testdata/stdlib_smoke_test.jsonnet | 44 ++++++++++++++++++++++++------ 2 files changed, 44 insertions(+), 16 deletions(-) diff --git a/testdata/stdlib_smoke_test.golden b/testdata/stdlib_smoke_test.golden index 3b2e86390..700d7bfe5 100644 --- a/testdata/stdlib_smoke_test.golden +++ b/testdata/stdlib_smoke_test.golden @@ -1,11 +1,11 @@ { "abs": 42, - "acos": 1.0471975511965976, + "acos": true, "asciiLower": "blah", "asciiUpper": "BLAH", - "asin": 0.52359877559829893, + "asin": true, "assertEqual": true, - "atan": 1.3734007669450157, + "atan": true, "base64": [ "YmxhaA==", "YmxhaA==" @@ -21,7 +21,7 @@ "ceil": 5, "char": "A", "codepoint": 65, - "cos": 0.2836621854632263, + "cos": true, "count": 1, "decodeUTF8": "AAA", "encodeUTF8": [ @@ -101,7 +101,7 @@ "join": "a,b,c", "length": 0, "lines": "a\nb\nc\n", - "log": 1.6094379124341003, + "log": true, "lstripChars": "bbbbcccc", "makeArray": [ 0, @@ -222,7 +222,7 @@ ] ], "sign": 1, - "sin": -0.95892427466313845, + "sin": true, "slice": "o", "sort": [ [ @@ -249,7 +249,7 @@ "a,b", "c" ], - "sqrt": 2.2360679774997898, + "sqrt": true, "startsWith": true, "strReplace": "bba", "stringChars": [ @@ -260,7 +260,7 @@ ], "stripChars": "bbbb", "substr": "s", - "tan": -3.3805150062465854, + "tan": true, "thisFile": "testdata/stdlib_smoke_test", "toString": "42", "type": "object", diff --git a/testdata/stdlib_smoke_test.jsonnet b/testdata/stdlib_smoke_test.jsonnet index ca9ccf8bf..339625bbf 100644 --- a/testdata/stdlib_smoke_test.jsonnet +++ b/testdata/stdlib_smoke_test.jsonnet @@ -4,6 +4,34 @@ // Functions without optional arguments need only one line // Functions with optional arguments need two lines - one with none of the optional arguments // and the other with all of them. +local assertClose(a, b) = + // Using 1e-12 as tolerance. Jsonnet uses double-precision floats with machine epsilon of 2**-53 ≈ 1.11e-16. + // This tolerance is ~9000x the machine epsilon, which is quite lenient and should work across + // different platforms and math libraries. + // + // We use a combination of absolute and relative error to handle both small and large values: + // - For values near zero, we use absolute error to avoid division issues + // - For larger values, we use relative error to maintain precision + // + // This correctly handles cases like: + // assertClose(1e-15, 0) - should pass (both are essentially zero) + // assertClose(-100, 0) - should fail (significant difference) + // assertClose(std.sin(std.pi), 0) - should pass (tiny floating point error) + local abs_a = std.abs(a); + local abs_b = std.abs(b); + local diff = std.abs(a - b); + local max_abs = std.max(abs_a, abs_b); + local err = + if abs_a == 0 && abs_b == 0 then + 0 // Both are exactly zero, so no error + else if max_abs < 1e-12 then + diff // For very small values, use absolute error + else + diff / max_abs; // For larger values, use relative error + if err > 1e-12 then + error 'Assertion failed (error ' + err + '). ' + a + ' !~ ' + b + else + true; { // extVar and native are skipped here, because of the special setup required. @@ -45,18 +73,18 @@ min: std.min(a=2, b=3), pow: std.pow(x=2, n=3), exp: std.exp(x=5), - log: std.log(x=5), + log: assertClose(std.log(x=5), 1.6094379124341003), exponent: std.exponent(x=5), mantissa: std.mantissa(x=5), floor: std.floor(x=5), ceil: std.ceil(x=5), - sqrt: std.sqrt(x=5), - sin: std.sin(x=5), - cos: std.cos(x=5), - tan: std.tan(x=5), - asin: std.asin(x=0.5), - acos: std.acos(x=0.5), - atan: std.atan(x=5), + sqrt: assertClose(std.sqrt(x=5), 2.2360679774997898), + sin: assertClose(std.sin(x=5), -0.9589242746631385), + cos: assertClose(std.cos(x=5), 0.2836621854632263), + tan: assertClose(std.tan(x=5), -3.3805150062465854), + asin: assertClose(std.asin(x=0.5), 0.52359877559829893), + acos: assertClose(std.acos(x=0.5), 1.0471975511965976), + atan: assertClose(std.atan(x=5), 1.3734007669450157), // Assertions and debugging assertEqual: std.assertEqual(a="a", b="a"),