Skip to content

Commit 4487bfb

Browse files
authored
Added constant pi and several math functions (#1187)
Add constant pi and several math functions Added: * pi (up to IEEE 64-bit binary float precision) * deg2rad, rad2deg * atan2 (builtin using C/C++ std library) * hypot (builtin using C/C++ std library) * log2, log10
1 parent 2b0122c commit 4487bfb

File tree

7 files changed

+77
-17
lines changed

7 files changed

+77
-17
lines changed

core/desugarer.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ struct BuiltinDecl {
3636
std::vector<UString> params;
3737
};
3838

39-
static unsigned long max_builtin = 38;
39+
static unsigned long max_builtin = 40;
4040
BuiltinDecl jsonnet_builtin_decl(unsigned long builtin)
4141
{
4242
switch (builtin) {
@@ -79,6 +79,8 @@ BuiltinDecl jsonnet_builtin_decl(unsigned long builtin)
7979
case 36: return {U"parseYaml", {U"str"}};
8080
case 37: return {U"encodeUTF8", {U"str"}};
8181
case 38: return {U"decodeUTF8", {U"arr"}};
82+
case 39: return {U"atan2", {U"y", U"x"}};
83+
case 40: return {U"hypot", {U"a", U"b"}};
8284
default:
8385
std::cerr << "INTERNAL ERROR: Unrecognized builtin function: " << builtin << std::endl;
8486
std::abort();

core/vm.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -937,6 +937,8 @@ class Interpreter {
937937
builtins["parseYaml"] = &Interpreter::builtinParseYaml;
938938
builtins["encodeUTF8"] = &Interpreter::builtinEncodeUTF8;
939939
builtins["decodeUTF8"] = &Interpreter::builtinDecodeUTF8;
940+
builtins["atan2"] = &Interpreter::builtinAtan2;
941+
builtins["hypot"] = &Interpreter::builtinHypot;
940942

941943
DesugaredObject *stdlib = makeStdlibAST(alloc, "__internal__");
942944
jsonnet_static_analysis(stdlib);
@@ -1099,6 +1101,20 @@ class Interpreter {
10991101
return nullptr;
11001102
}
11011103

1104+
const AST *builtinAtan2(const LocationRange &loc, const std::vector<Value> &args)
1105+
{
1106+
validateBuiltinArgs(loc, "atan2", args, {Value::NUMBER, Value::NUMBER});
1107+
scratch = makeNumberCheck(loc, std::atan2(args[0].v.d, args[1].v.d));
1108+
return nullptr;
1109+
}
1110+
1111+
const AST *builtinHypot(const LocationRange &loc, const std::vector<Value> &args)
1112+
{
1113+
validateBuiltinArgs(loc, "hypot", args, {Value::NUMBER, Value::NUMBER});
1114+
scratch = makeNumberCheck(loc, std::hypot(args[0].v.d, args[1].v.d));
1115+
return nullptr;
1116+
}
1117+
11021118
const AST *builtinType(const LocationRange &, const std::vector<Value> &args)
11031119
{
11041120
switch (args[0].t) {

doc/_stdlib_gen/stdlib-content.jsonnet

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ local html = import 'html.libsonnet';
9898
<ul><code>std.pow(x, n)</code></ul>
9999
<ul><code>std.exp(x)</code></ul>
100100
<ul><code>std.log(x)</code></ul>
101+
<ul><code>std.log2(x)</code></ul>
102+
<ul><code>std.log10(x)</code></ul>
101103
<ul><code>std.exponent(x)</code></ul>
102104
<ul><code>std.mantissa(x)</code></ul>
103105
<ul><code>std.floor(x)</code></ul>
@@ -109,12 +111,19 @@ local html = import 'html.libsonnet';
109111
<ul><code>std.asin(x)</code></ul>
110112
<ul><code>std.acos(x)</code></ul>
111113
<ul><code>std.atan(x)</code></ul>
114+
<ul><code>std.atan2(y, x)</code></ul>
115+
<ul><code>std.deg2rad(x)</code></ul>
116+
<ul><code>std.rad2deg(x)</code></ul>
117+
<ul><code>std.hypot(a, b)</code></ul>
112118
<ul><code>std.round(x)</code></ul>
113119
<ul><code>std.isEven(x)</code></ul>
114120
<ul><code>std.isOdd(x)</code></ul>
115121
<ul><code>std.isInteger(x)</code></ul>
116122
<ul><code>std.isDecimal(x)</code></ul>
117123
</ul>
124+
<p>
125+
The constant <code>std.pi</code> is also available.
126+
</p>
118127
<p>
119128
The function <code>std.mod(a, b)</code> is what the % operator is desugared to. It performs
120129
modulo arithmetic if the left hand side is a number, or if the left hand side is a string,

doc/ref/spec.html

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2825,7 +2825,10 @@ <h4 id="execution">Execution</h4>
28252825
<code>std.asin(x)</code>,
28262826
<code>std.acos(x)</code>,
28272827
<code>std.atan(x)</code>,
2828+
<code>std.atan2(y, x)</code>,
28282829
<code>std.log(x)</code>,
2830+
<code>std.log2(x)</code>,
2831+
<code>std.log10(x)</code>,
28292832
<code>std.exp(x)</code>,
28302833
<code>std.mantissa(x)</code>,
28312834
<code>std.exponent(x)</code> and

doc/ref/stdlib.html

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,8 @@ <h3 id="math">
234234
<ul><code>std.pow(x, n)</code></ul>
235235
<ul><code>std.exp(x)</code></ul>
236236
<ul><code>std.log(x)</code></ul>
237+
<ul><code>std.log2(x)</code></ul>
238+
<ul><code>std.log10(x)</code></ul>
237239
<ul><code>std.exponent(x)</code></ul>
238240
<ul><code>std.mantissa(x)</code></ul>
239241
<ul><code>std.floor(x)</code></ul>
@@ -245,6 +247,9 @@ <h3 id="math">
245247
<ul><code>std.asin(x)</code></ul>
246248
<ul><code>std.acos(x)</code></ul>
247249
<ul><code>std.atan(x)</code></ul>
250+
<ul><code>std.atan2(y, x)</code></ul>
251+
<ul><code>std.deg2rad(x)</code></ul>
252+
<ul><code>std.rad2deg(x)</code></ul>
248253
<ul><code>std.round(x)</code></ul>
249254
<ul><code>std.isEven(x)</code></ul>
250255
<ul><code>std.isOdd(x)</code></ul>

stdlib/std.jsonnet

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,15 @@ limitations under the License.
261261
else
262262
error 'Operator % cannot be used on types ' + std.type(a) + ' and ' + std.type(b) + '.',
263263

264+
// this is the most precision that will fit in a f64
265+
pi:: 3.14159265358979311600,
266+
267+
deg2rad(x):: x * std.pi / 180,
268+
rad2deg(x):: x * 180 / std.pi,
269+
270+
log2(x):: std.log(x) / std.log(2),
271+
log10(x):: std.log(x) / std.log(10),
272+
264273
map(func, arr)::
265274
if !std.isFunction(func) then
266275
error ('std.map first param must be function, got ' + std.type(func))

test_suite/stdlib.jsonnet

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -56,31 +56,47 @@ std.assertEqual(std.abs(33), 33) &&
5656
std.assertEqual(std.abs(-33), 33) &&
5757
std.assertEqual(std.abs(0), 0) &&
5858

59-
// Ordinary (non-test) code can define pi as 2*std.acos(0)
60-
local pi = 3.14159265359;
61-
62-
assertClose(std.sin(0.0 * pi), 0) &&
63-
assertClose(std.sin(0.5 * pi), 1) &&
64-
assertClose(std.sin(1.0 * pi), 0) &&
65-
assertClose(std.sin(1.5 * pi), -1) &&
66-
assertClose(std.sin(2.0 * pi), 0) &&
67-
assertClose(std.cos(0.0 * pi), 1) &&
68-
assertClose(std.cos(0.5 * pi), 0) &&
69-
assertClose(std.cos(1.0 * pi), -1) &&
70-
assertClose(std.cos(1.5 * pi), 0) &&
71-
assertClose(std.cos(2.0 * pi), 1) &&
59+
assertClose(std.sin(0.0 * std.pi), 0) &&
60+
assertClose(std.sin(0.5 * std.pi), 1) &&
61+
assertClose(std.sin(1.0 * std.pi), 0) &&
62+
assertClose(std.sin(1.5 * std.pi), -1) &&
63+
assertClose(std.sin(2.0 * std.pi), 0) &&
64+
assertClose(std.cos(0.0 * std.pi), 1) &&
65+
assertClose(std.cos(0.5 * std.pi), 0) &&
66+
assertClose(std.cos(1.0 * std.pi), -1) &&
67+
assertClose(std.cos(1.5 * std.pi), 0) &&
68+
assertClose(std.cos(2.0 * std.pi), 1) &&
7269
assertClose(std.tan(0), 0) &&
73-
assertClose(std.tan(0.25 * pi), 1) &&
70+
assertClose(std.tan(0.25 * std.pi), 1) &&
7471
assertClose(std.asin(0), 0) &&
7572
assertClose(std.acos(1), 0) &&
76-
assertClose(std.asin(1), 0.5 * pi) &&
77-
assertClose(std.acos(0), 0.5 * pi) &&
73+
assertClose(std.asin(1), 0.5 * std.pi) &&
74+
assertClose(std.acos(0), 0.5 * std.pi) &&
7875
assertClose(std.atan(0), 0) &&
76+
assertClose(std.atan2(1, 1), std.pi / 4) &&
77+
assertClose(std.atan2(-1, 1), -std.pi / 4) &&
78+
assertClose(std.atan2(1.2, -3.8), 2.835713782184941) && // arbitrary, done on a calculator
79+
assertClose(std.deg2rad(0), 0) &&
80+
assertClose(std.deg2rad(45), std.pi / 4) &&
81+
assertClose(std.deg2rad(90), std.pi / 2) &&
82+
assertClose(std.deg2rad(172), 3.0019663134302466) && // arbitrary, done on a calculator
83+
assertClose(std.rad2deg(std.pi / 4), 45) &&
84+
assertClose(std.rad2deg(std.pi / 2), 90) &&
85+
assertClose(std.rad2deg(3.0019663134302466), 172) && // arbitrary, done on a calculator
86+
assertClose(std.hypot(3, 4), 5) &&
87+
assertClose(std.hypot(5, 12), 13) &&
88+
assertClose(std.hypot(1, 1), std.sqrt(2)) &&
7989
assertClose(std.log(std.exp(5)), 5) &&
8090
assertClose(std.mantissa(1), 0.5) &&
8191
assertClose(std.exponent(1), 1) &&
8292
assertClose(std.mantissa(128), 0.5) &&
8393
assertClose(std.exponent(128), 8) &&
94+
assertClose(std.log2(std.pow(2, -5)), -5) &&
95+
assertClose(std.log2(std.pow(2, 0)), 0) &&
96+
assertClose(std.log2(std.pow(2, std.pi)), std.pi) &&
97+
assertClose(std.log10(std.pow(10, -5)), -5) &&
98+
assertClose(std.log10(std.pow(10, 0)), 0) &&
99+
assertClose(std.log10(std.pow(10, std.pi)), std.pi) &&
84100

85101
std.assertEqual(std.clamp(-3, 0, 5), 0) &&
86102
std.assertEqual(std.clamp(4, 0, 5), 4) &&

0 commit comments

Comments
 (0)