I have this ugly code:
if ( v > 10 ) size = 6;
if ( v > 22 ) size = 5;
if ( v > 51 ) size = 4;
if ( v > 68 ) size = 3;
if ( v > 117 ) size = 2
Using the NavigableMap
API :
NavigableMap<Integer, Integer> s = new TreeMap<Integer, Integer>();
s.put(10, 6);
s.put(22, 5);
s.put(51, 4);
s.put(68, 3);
s.put(117, 2);
s.put(145, 1);
return s.lowerEntry(v).getValue();
The most obvious problem with the OPs solution is branching, so I would suggest a polynomial regression. This will result in a nice branchless expression on the form
size = round(k_0 + k_1 * v + k_2 * v^2 + ...)
You will of course not get an exact result, but if you can tolerate some deviance it's a very performant alternative. Since the 'leave unmodified' behavior of to original function for values where v<10
is impossible to model with a polynomial, I took the liberty of assuming a zero-order hold interpolation for this region.
For a 45-degree polynomial with the following coefficients,
-9.1504e-91 1.1986e-87 -5.8366e-85 1.1130e-82 -2.8724e-81 3.3401e-78 -3.3185e-75 9.4624e-73 -1.1591e-70 4.1474e-69 3.7433e-67 2.2460e-65 -6.2386e-62 2.9843e-59 -7.7533e-57 7.7714e-55 1.1791e-52 -2.2370e-50 -4.7642e-48 3.3892e-46 3.8656e-43 -6.0030e-41 9.4243e-41 -1.9050e-36 8.3042e-34 -6.2687e-32 -1.6659e-29 3.0013e-27 1.5633e-25 -8.7156e-23 6.3913e-21 1.0435e-18 -3.0354e-16 3.8195e-14 -3.1282e-12 1.8382e-10 -8.0482e-09 2.6660e-07 -6.6944e-06 1.2605e-04 -1.7321e-03 1.6538e-02 -1.0173e-01 8.3042e-34 -6.2687e-32 -1.6659e-29 3.0013e-27 1.5633e-25 -8.7156e-23 6.3913e-21 1.0435e-18 -3.0354e-16 3.8195e-14 -3.1282e-12 1.8382e-10 -8.0482e-09 2.6660e-07 -6.6944e-06 1.2605e-04 -1.7321e-03 1.6538e-02 -1.0173e-01 3.6100e-01 -6.2117e-01 6.3657e+00
, you get a beautifully fitted curve:
And as you can see, you get an 1-norm error of just 1.73 across the whole range from 0 to 200*!
*Results for v∉[0,200]
may vary.
The obvious answer is to use Groovy:
def size = { v -> [145,117,68,51,22,10].inject(1) { s, t -> v > t ? s : s + 1 } }
One liners are always better. Returns 7 for the undefined case where v <= 10.
Is there an underlying mathematical rule to this? If so you should use that: but only if it comes from the problem domain, not just some formula that happens to fit the cases.
return v > 145 ? 1
: v > 117 ? 2
: v > 68 ? 3
: v > 51 ? 4
: v > 22 ? 5
: v > 10 ? 6
: "put inital size value here";
You could rewrite it in ARM code. It's only 7 cycles worst case and a slender 164 bytes. Hope that helps. (note: this is untested)
; On entry
; r0 - undefined
; r1 - value to test
; lr - return address
; On exit
; r0 - new value or preserved
; r1 - corrupted
;
wtf
SUBS r1, r1, #10
MOVLE pc, lr
CMP r1, #135
MOVGT r0, #1
ADRLE r0, lut
LDRLEB r0, [r0, r1]
MOV pc, lr
;
; Look-up-table
lut
DCB 0 ; padding
DCB 6 ; r1 = 11 on entry
DCB 6
DCB 6
DCB 6
DCB 6
DCB 6
DCB 6
DCB 6
DCB 6
DCB 6
DCB 6
DCB 6
DCB 5 ; r1 = 23 on entry
DCB 5
...
ALIGN