SJT1
March 9, 2022, 12:26pm
1
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”
up:{[x;nd]string%[;s]ceiling xs: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.
SJT1
March 10, 2022, 11:19am
3
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
dnnr!(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.)
Rolf1
March 10, 2022, 9:45pm
4
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]}
SJT1
March 12, 2022, 9:48am
5
Eliminating up
and dn
is a good move, but that doesnt quite work.
q)rnd:{(up
dnnr!(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]
SJT1
March 15, 2022, 9:24am
6
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+
.
Spoiler rnd:{[x;nd;m] string%;s @: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