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
rndwithout 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
eachcan be dispensed with. Bothupanddntake vector arguments..Q.fdoes 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
upanddnfunctions 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
rndis 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}ndderives a scaling factors, used to multiplyx.It remains to round – up, down, or nearest integer – and divide by
sbefore 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?mevaluates to a function atom ifmis an atom; to a list if a vector. All the functions are atomic, so the function or functions can be applied toxby@\:. -
In the sterling currency before 1971, twelve pennies made a shilling, and twenty shillings a pound.
Write
nearestto roundyto the nearest multiple ofxso thatnearest[12]rounds pennies to shillings, andnearest[20]shillings to pounds.Make
nearestatomic. (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
nearestto 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