If possible, I'd like a function f(i,j)=k defined as follows

  1. I'm writing a piece of code and I want to simplify a bunch of if/else statements.

    I need f:{-1,1}x{-1,1}-->{1,2,3,4} with

    f(1,-1)=1
    f(1,1)=2
    f(-1,1)=3
    f(-1,-1)=4


    Can anyone think of a mathematical function that will give me the desired output?
     
  2. jcsd
  3. In other words, I want a fancy way of simplifying

    Code (Text):

         if (dx == 1 && dy == -1)
            th = 1;
         else if (dx == 1 && dy == 1)
            th = 2;
         else if (dx == -1 && dy == 1)
            th = 3;
         else // (dx == -1 && dy == -1)
            th == 4;
     
    I want to write 1 line:

    Code (Text):

    th = ??? // some operation(s) on dx and dy
     
     
  4. Mark44

    Staff: Mentor

    I haven't given much though to a math function to do this, but you could simplify your if block like so:
    Code (Text):
    if (dx == 1)
    {
       th = (int)(1.5 + 0.5 * dy);
    }
    else if (dx == -1)
    {
       th = (int)(3.5  - 0.5 *dy);
    }
     
    If there are only the four possible combinations of -1 and 1, the else clause I have above could be further simplified by changing "else if (dx == -1)" to simply "else".
     
    Last edited: Apr 19, 2014
  5. I just did some curve fitting in Excel and got this;

    =-(1/6)*(dx+2*dy)^3+(1/8)*(dx+2*dy)^2+(7/6)*(dx+2*dy)+(15/8)

    In Excel that rounds to the exact numbers you need. If that doesnt round correctly for you, you can do a higher order fit.

    Probably not the "best" function, but its "a" function. :)
     
  6. jbunniii

    jbunniii 3,353
    Science Advisor
    Homework Helper
    Gold Member

    How about
    $$f(x,y) = -x + \frac{5 + xy}{2}$$
    Solved by presuming a form ##f(x,y) = ax + by + c + dxy##, which gives us the following 4x4 linear equation
    $$\begin{bmatrix} 1 & -1 & 1 & -1 \\
    1 & 1 & 1 & 1 \\
    -1 & 1 & 1 & -1 \\
    -1 & -1 & 1 & 1\\
    \end{bmatrix} \begin{bmatrix} a \\ b \\ c \\ d \\ \end{bmatrix} = \begin{bmatrix} 1 \\ 2 \\ 3 \\ 4 \\ \end{bmatrix}$$
    I let Matlab do the dirty work, which gave me ##a=-1, b = 0, c = 5/2, d = 1/2##.
     
    Last edited: Apr 18, 2014
  7. Did you know there could be a solution of that form before letting Matlab do the dirty work?
     
  8. jbunniii

    jbunniii 3,353
    Science Advisor
    Homework Helper
    Gold Member

    At first I thought there would be a solution of the form ##ax + by + c##: first linearly map the values of ##x## into 0 and 1, and the same with ##y##, then map the resulting pair into the values 0, 1, 2, 3 (binary representation with two "bits"), then add one. It would have worked if he had wanted

    f(1,-1)=1
    f(1,1)=2
    f(-1,-1)=3
    f(-1,1)=4

    but his map reverses the 3 and 4. If this had worked, the problem would have had 4 equations and 3 unknowns, but the 4th equation would be a linear combination of the first 3, hence consistent Since it didn't work, I needed a 4th unknown, thus one more term involving ##x## and ##y##. Instead of ##dxy## you can use ##d## times just about any function ##g(x,y)## as long as the 4th column of the matrix is linearly independent of the first three. But ##xy## has the advantage of being easy to calculate for ##x,y = \pm 1##. :biggrin:
     
    1 person likes this.
  9. jbunniii

    jbunniii 3,353
    Science Advisor
    Homework Helper
    Gold Member

    P.S. As it happens, we only needed 3 unknowns, namely ##a,c,d##, since ##b## ended up being zero. So I could have used the form ##ax + c + dxy##. But I didn't know that until after the fact.
     
  10. jim mcnamara

    jim mcnamara 1,483
    Science Advisor
    Gold Member

    Simplifying code to a math function is probably not a great idea, in this particular case, although it is really interesting.

    Mark's simplification is still readable.

    Something to solve jbunnii's function would not be inherently enlightening nor would it be "self documenting" the way Mark's code is.

    And the machine code for if/else is really elementary and fast. jbunnii's function is actually quite cool, but it involves 2 additions, a negation, a multiplication and a division. So if this has to be fast it may be possible the division could slow you down. Depends on your platform and compiler.

    My comment about performance was posted without seeing jbunnii's last post. Oops.

    FWIW, if you don't care about overhead, create an associative array, then statically assign results {1...4} to each element:
    Code (Text):
    th = assoc_arr[ to_string(dx, dy)];
    . This is more than bit much, but the result is just as elegant as the math function approach.

    If you have many if then else checks, consider changing to a switch() construct. Function pointer arrays are great for simplifying multiple branches into functions that take identical datatypes.
    http://www.newty.de/fpt/fpt.html#arrays
     
  11. jbunniii

    jbunniii 3,353
    Science Advisor
    Homework Helper
    Gold Member

    Agree fully with jim mcnamara that you should NOT implement it this way in software if you care about efficiency and, much more importantly, readability/maintainability. In my day job as a software engineer, if I were to encounter a smartass function like this in our source code, I would want to strangle whoever wrote it. But it would be an interesting interview question. :tongue:

    Much better to write something like your original code:
    Code (Text):

         if (dx == 1 && dy == -1)
            th = 1;
         else if (dx == 1 && dy == 1)
            th = 2;
         else if (dx == -1 && dy == 1)
            th = 3;
         else // (dx == -1 && dy == -1)
            th == 4;
     
    [edit] removed alternate code which calculated the wrong answer
     
  12. Mark44

    Staff: Mentor

    jbunni, I agree. I don't see any problem with the if ... else block as shown in post #2. "Clever" code is seldom the best way to go, and a straightforward algorithm is to be preferred, not least for the sake of being more understandable to the maintenance programmer.
     
  13. Good answers, guys. Thanks!
     
  14. x= 1+(1-i)+(j*i+1)/2 works.
    But I agree that simpler is better in programming.
    You can use the if/then or define a doubly-dimensioned array to look up the correct value.
     
  15. AlephZero

    AlephZero 7,300
    Science Advisor
    Homework Helper

    If you want speed, just use a lookup table.
    Code (Text):

    static const int fdata[2][2] = {{4,0,3},{0,0,0},{(1,0,2}};

    int f(int x, int y)
    {
        return fdata[x+1][y+1];
    }
     
     
  16. Mark44

    Staff: Mentor

    The fdata array has too many elements in it. You're probably thinking that the array is 3 X 3, and that the indexes run 0, 1, 2. There is also an extra left paren in the last group of three numbers.
     
  17. AlephZero

    AlephZero 7,300
    Science Advisor
    Homework Helper

    True. I mostly use languages that support arrays properly (unlike C and C++), so the dimensions would run from -1 to 1 and you would just return fdata(i.j).
     
  18. Mark44

    Staff: Mentor

    Unless you're referring to Fortran, then whatever languages you're talking about are newer than C, which has been around since the early 70's. Newer languages don't have the need to maintain compatability with existing code, so can start on a clean page. For me, it's not a hardship to forgo negative array subscripts.
     
  19. jbunniii

    jbunniii 3,353
    Science Advisor
    Homework Helper
    Gold Member

    As a side note, I will point out that it is possible to use negative indices in C and C++. For example, I can write

    Code (Text):

    int data[] = {1, 2, 3};
    int *pData = &data[1];
     
    Then I can access the elements of the array using either data[0],data[1],data[2] or pData[-1],pData[0],pData[1].

    For two-dimensional arrays it can still be done, but setting it up is uglier.

    Code (Text):

    int data[3][3] = {{1,2,3}, {4,5,6}, {7,8,9}};
    int *pData[3] = {&data[0][1], &data[1][1], &data[2][1]};
    int **ppData = &pData[1];
     
    This allows me to write ppData[n-1][m-1] instead of data[m][n], where ##0 \leq m,n \leq 2##.

    It's usually too hideous to contemplate doing this sort of thing in code for public consumption, but if you encapsulate the ugly implementation in a class, the ability to use negative subscripts can sometimes make the code that uses the array clearer, e.g. if the 2d array represents a kernel being used in an image processing operation.
     
  20. The original solution by Mark44 is a simple, direct solution. (The dimensions were off and a typo, but without a compiler it is hard to get it right the first time.) Regarding array indices and table look-ups, nothing can beat the versatility of well implemented associative arrays (aka hash tables, dictionaries, etc.). C++ hash tables (unordered_map) are awkward to use, Perl is very good, Python looks good but I have no experience with it.
     
  21. Mark44

    Staff: Mentor

    I'm not sure what you're talking about. I didn't use arrays at all. You might be referring to the code that AlephZero wrote that I quoted in one post.
     
Know someone interested in this topic? Share a link to this question via email, Google+, Twitter, or Facebook

Have something to add?

0
Draft saved Draft deleted