My function only works if I use std.trace() in it

82 views
Skip to first unread message

Sebastien Diot

unread,
May 4, 2023, 2:15:13 PM5/4/23
to Jsonnet
Since jsonnet doesn't currently has "big integer" support, I decided to try and implement it myself, as I don't want to wait until it gets added, if ever.

I now have a sufficiently complete jsonnet library, that should fill my need, but I have problems with the last function added: "euclide(a,b)"
It should use integer division of a by b, and return both the quotient and the modulo.

I've used the second implementation here:


The function test dies with:

TRACE: int.libjsonnet:607 euclideRecurs["9223372036854775808", "2"]
RUNTIME ERROR: max stack frames exceeded.
        int.libjsonnet:475:30-31        thunk from <thunk <aTmp> from <function <anonymous>>>
        int.libjsonnet:351:26-29        thunk from <thunk <isNum> from <function <anonymous>>>
        int.libjsonnet:351:17-30        thunk <isNum> from <function <anonymous>>
        int.libjsonnet:352:19-24        thunk <num2> from <function <anonymous>>
        int.libjsonnet:353:25-29        thunk from <thunk <sign> from <function <anonymous>>>
        <std>:835:22-23 thunk from <function <anonymous>>
        <std>:29:26-27  thunk from <function <anonymous>>
        <std>:29:17-28  function <anonymous>
        <std>:835:9-24  function <anonymous>
        int.libjsonnet:353:16-30        thunk <sign> from <function <anonymous>>
        ...
        int.libjsonnet:493:3-29 function <anonymous>
        int.libjsonnet:619:18-32        thunk from <function <newQR2>>
        int.libjsonnet:617:6-8  thunk from <function <newQR2>>
        int.libjsonnet:626:20-27        thunk from <function <loop>>
        int.libjsonnet:623:6-8  thunk from <function <loop>>
        <std>:823:8-14  function <anonymous>
        int_test.jsonnet:467:9-88       function <test_divmod>
        int_test.jsonnet:478:18-31      object <anonymous>
        Field "result"
        During manifestation

But if I add std.trace() in it, to debug what is wrong, it suddenly works!
So, the code is actually correct, but somehow won't work as is.
I blame "lazy evaluation" here, as I assume using std.trace() forces the "VM" to evaluate values "early".

I have problem building the C++ version, so I've switched to the GO version, which seems to be 100X faster, so I guess it's for the better.

As the function relies on integer addition, subtraction and multiplication, I cannot give a "small example", but all code is OSS and can be found here:


The error can be reproduced by running "jsonnet int_test.jsonnet"

The file int.libjsonnet has multiple variants of "euclide".

This one fails:

    local euclideRecurs(a,bbbbbb) =
        local b = std.trace("euclideRecurs"+std.toString([a,bbbbbb]), bbbbbb);
        # We need division to implement division! But x/10 can be implemented without / ...
        local newN2(ax,n) =
            if int.gt(int.mult(b, n), ax) then
                n
            else
                newN2(ax,mult10(n));
        local newN(ax,n) = div10(newN2(ax,n));
        local newQR2(bn,nx,qx,rx) =
            if int.lt(rx, bn) then
                [qx,rx]
            else
                newQR2(bn,nx,int.add(qx,nx),int.sub(rx,bn));
        local newQR(nx,qx,rx) = newQR2(int.mult(b, nx),nx,qx,rx);
        local loop(ax,nx,qx,rx) =
            if int.lt(rx, b) then
                [qx,rx]
            else
                local qxrx = newQR(newN(ax,nx),qx,rx);
                loop(qxrx[1],1,qxrx[0],qxrx[1]);
        loop(a,1,0,a),


This one works, and the only differences should be the use of std.trace().

    local euclideRecursTrace(a,bbbbbb) =
        local b = std.trace("euclideRecurs"+std.toString([a,bbbbbb]), bbbbbb);
        # We need division to implement division! But x/10 can be implemented without / ...
        local newN2(ax,n) =
            if int.gt(int.mult(b, n), ax) then
                n
            else
                newN2(ax,mult10(n));
        local newN(ax,n) = std.trace("newN"+std.toString([ax,n]), div10(newN2(ax,n)));
        local newQR2(bn,nx,qx,rx) =
            if int.lt(rx, bn) then
                [qx,rx]
            else
                newQR2(bn,nx,int.add(qx,nx),int.sub(rx,bn));
        local newQR(nx,qx,rx) = std.trace("newQR"+std.toString([nx,qx,rx]), newQR2(int.mult(b, nx),nx,qx,rx));
        local loop(ax,nx,qx,rxxx) =
            local rx = std.trace("loop"+std.toString([ax,nx,qx,rxxx]), rxxx);
            if int.lt(rx, b) then
                [qx,rx]
            else
                local qxrx = newQR(newN(ax,nx),qx,rx);
                loop(qxrx[1],1,qxrx[0],qxrx[1]);
        loop(a,1,0,a),


How do I get this to work without using std.trace()?

Regards,
Sebastien Diot
Reply all
Reply to author
Forward
0 new messages