Get around
From a question on StackOverflow…
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"
Some music to listen to while you work on this.
Exercises
-
Write
rnd
without any control words (do
,while
,if
, Cond$
).Solution by calummack
Solves (1). Note the use of a dictionary where another language would need a control structure.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}
The
each
can be dispensed with. Bothup
anddn
take vector arguments..Q.f
does not, sod[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
anddn
functions differ by only a single keyword! 😖 And without delegating one of the modes to.Q.f
? -
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"
A single-expression
rnd
is possible, <80 characters.Solution by jbetz34
Here the number of decimalsrnd:{[x;nd;m] string%[;s]((ceiling;floor;7h$)`up`dn`nr?m)@\:x*s:10 xexp nd}
nd
derives a scaling factors
, used to multiplyx
.It remains to round – up, down, or nearest integer – and divide by
s
before casting to string.Rounding to the nearest integer would be composition
floor 0.5+
, but projection7h$
(cast to long) does it implicitly.Expression
(ceiling;floor;7h$)`up`dn`nr?m
evaluates to a function atom ifm
is an atom; to a list if a vector. All the functions are atomic, so the function or functions can be applied tox
by@\:
. -
In the sterling currency before 1971, twelve pennies made a shilling, and twenty shillings a pound.
Write
nearest
to roundy
to the nearest multiple ofx
so thatnearest[12]
rounds pennies to shillings, andnearest[20]
shillings to pounds.Make
nearest
atomic. (No loops are necessary.)Solution
(Were you expecting something more complicated?)nearest:{x*7h$y%x} q)nearest[12]7 13 19 24 31 12 12 24 24 36 q)nearest[20]7 13 19 24 31 0 20 20 20 40
-
Extend
nearest
to accept vectorx
.Solution
nearest:{x*7h$y%/:x} q)nearest[12 20]7 13 19 24 31 12 12 24 24 36 0 20 20 20 40