SJT
March 9, 2022, 12:00am
1
https://learninghub.kx.com/forums/topic/five-easy-pieces-2-getting-around
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
October 3, 2022, 12:00am
2
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.)
SJT
December 3, 2022, 12:00am
3
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
March 19, 2024, 10:55am
4
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+
.
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.
rolf
October 3, 2022, 12:00am
6
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]}
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