KX Community

Find answers, ask questions, and connect with our KX Community around the world.
KX Community Guidelines

Home Forums kdb+ Five easy pieces #2: getting around

  • Five easy pieces #2: getting around

    Posted by SJT on March 9, 2022 at 12:00 am

    From a recent question on Stack Overflow:

    q)q:9.638554216867471 
    q)rnd[q;2;`up] / round up 
    "9.64" 
    q)rnd[q;2;`dn] / round down 
    "9.63" 
    q)rnd[q;2;`nr] / round to nearest 
    "9.64" 
    q)rnd[q+0 1 2;3;`up] 
    "9.639" "10.639" "11.639"

    Write rnd without any control words (do, while, if, Cond $). For bonus points extend to multiple modes (3rd argument):

    q)rnd[q+0 1 2;3;`up`dn] 
    "9.639" "10.639" "11.639" "9.638" "10.638" "11.638"
    SJT replied 8 months, 2 weeks ago 4 Members · 6 Replies
  • 6 Replies
  • calummack

    Member
    September 3, 2022 at 12:00 am
    up:{[x;nd]string%[;s]ceiling x*s:10 xexp nd}; 
    dn:{[x;nd]string%[;s]floor x*s:10 xexp nd}; 
    rnd:{[x;nd;m] d:`up`dn`nr!(up[;nd];dn[;nd];.Q.f[nd;]); (d m) each x};

    Seems to work.

  • SJT

    Member
    October 3, 2022 at 12:00 am

    Does the job! Note the use of a dictionary where another language would need a control structure.

    The each can be dispensed with. Both up and dn take vector arguments. .Q.f does not, so d[2] could be .Q.f'[nd;]:

     

    q)rnd:{[x;nd;m] d:`up`dn`nr!(up[;nd];dn[;nd];.Q.f'[nd;]); (d m) x} 
    q)rnd[q+0 1 2;3;`up] 
    "9.639" "10.639" "11.639" 
    q)rnd[q+0 1 2;3;`nr] 
    "9.639" "10.639" "11.639"

     

    Now: can we eliminate repetition? The up and dn functions differ by only a single keyword. And without delegating one of the modes to .Q.f?

    (Hint: a single expression rnd is possible, ?80 characters.)

  • rolf

    Member
    October 3, 2022 at 12:00 am

    building on the above

    rnd:{(`up`dn`nr!(f ceiling;(f:{string(x z*s)%s:10 xexp y})floor;.Q.f'))[z][;y;x]}

     

  • jbetz34

    Member
    October 4, 2022 at 12:00 am

     

    Spoiler
    rnd:{[x;nd;m] string%[;s]((ceiling;floor;7h$)`up`dn`nr?m)@:x*s:10 xexp nd}?

    Stealing your solution here, except floor 0.5+ can be replaced with 7h$. It is slightly more efficient and will save about 10 characters, if that matters

  • SJT

    Member
    December 3, 2022 at 12:00 am

    Eliminating up and dn is a good move, but that doesnt quite work.

     

    q)rnd:{(`up`dn`nr!(f ceiling;(f:{string(x z*s)%s:10 xexp y})floor;.Q.f'))[z][;y;x]} 
    q)q:9.638554216867471 
    q)rnd[q;2;`up] 
    {string(x z*s)%s:10 xexp y}[-_-:][;2;9.638554]

     

  • SJT

    Member
    March 19, 2024 at 10:55 am
    rnd:{[x;nd;m] string%[;s]((ceiling;floor;floor 0.5+)`up`dn`nr?m)@:x*s:10 xexp nd}

     

    Here the case structure is not a dictionary, just a mapping from the symbols to functions. The primitives all iterate implicitly: the Each Left : is used only to support multiple rounding modes.

    In the list of unary functions the third item floor 0.5+ is an implicit composition of two unaries: floor and the projection 0.5+.

Log in to reply.