Get rid of ugly if statements

后端 未结 25 1974
借酒劲吻你
借酒劲吻你 2020-12-02 05:59

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         


        
相关标签:
25条回答
  • 2020-12-02 06:31

    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();
    
    0 讨论(0)
  • 2020-12-02 06:31

    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:

    alt text

    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.

    0 讨论(0)
  • 2020-12-02 06:31

    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.

    0 讨论(0)
  • 2020-12-02 06:32

    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.

    0 讨论(0)
  • 2020-12-02 06:36
    return v > 145 ? 1 
         : v > 117 ? 2 
         : v > 68 ? 3 
         : v > 51 ? 4 
         : v > 22 ? 5 
         : v > 10 ? 6 
         : "put inital size value here";
    
    0 讨论(0)
  • 2020-12-02 06:37

    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
    
    0 讨论(0)
提交回复
热议问题