Codwiz51's Wiki

RSS

Navigation







Quick Search
»
Advanced Search »

DCDFLIB - Cleaning up labels and code flow

RSS
Modified on 2008/10/19 23:24 by Administrator Categorized as dcdflib
Administrator, 2008/10/19 11:23 I thought the following code clean up might be worth illustrating. In the dcdflib method beta_inc, there are a number of constructs similar to the following:


    if (x == 0.0) goto S210;
    if (y == 0.0) goto S230;
    if (a == 0.0) goto S240;
    if (b == 0.0) goto S220;

S210:
    //
    //  TERMINATION OF THE PROCEDURE
    //
    if (a == 0.0)
    {
        // x == 0 && a == 0
        ierr = 6;
        return;
    }
S220:
    w = 0.0;
    w1 = 1.0;
    return;
S230:
    if (b == 0.0)
    {
        ierr = 7;
        return;
    }
S240:
    w = 1.0;
    w1 = 0.0;
    return;


When I approach modifying this sort of code, I find it helpful to trace code execution and add comments to the code to help me keep track of the conditions that apply when a code block is executed. Here is the code with my comments added:


    // If we get to this point, we know that x + y == 1
    // a >= 0 && b >= 0
    // a != 0 && b != 0
    // test #1
    if (x == 0.0) goto S210;
    // test #2
    if (y == 0.0) goto S230;
    // test #3
    if (a == 0.0) goto S240;
    // test #4
    if (b == 0.0) goto S220;

S210:
    //
    //  TERMINATION OF THE PROCEDURE
    //
    // At this point, all we know is x == 0.0
    // The next test will fall through to label S220 if a != 0
    if (a == 0.0)
    {
        // x == 0 && a == 0
        ierr = 6;
        return;
    }
S220:
    // Two conditions can cause this code to execute
    // x == 0 and a != 0
    // or b == 0
    // There is a timing issue. The test for b == 0 occurs after
    // 'if' statements 2 & 3 have executed.
    w = 0.0;
    w1 = 1.0;
    return;
S230:
    // At this point, all we know is y == 0.0
    // The next test will fall through to label S240 if b != 0
    if (b == 0.0)
    {
        ierr = 7;
        return;
    }
S240:
    // Two conditions can cause this code to execute
    // y == 0 and b != 0
    // or a == 0
    w = 1.0;
    w1 = 0.0;
    return;


I used my notes from the above code block to layout a new set of if test blocks. The final code block is shown below.


    if (x == 0.0)
    {
        if (a == 0.0)
        {
            ierr = 6;
            return;
        }
        else
        {
            w = 0.0;
            w1 = 1.0;
            return;
        }
    }

    if (y == 0.0)
    {
        if (b == 0.0)
        {
            ierr = 7;
            return;
        }
        else
        {
            w = 1.0;
            w1 = 0.0;
            return;
        }
    }

    if (a == 0.0)
    {
        w = 1.0;
        w1 = 0.0;
        return;
    }

    if (b == 0.0)
    {
        w = 0.0;
        w1 = 1.0;
        return;
    }


This code reduces to the following:


    // if test #1
    if (x == 0.0)
    {
        if (a == 0.0)
        {
            ierr = 6;
            return;
        }
        else
        {
            w = 0.0;
            w1 = 1.0;
            return;
        }
    }

    // combined if tests #2 & #3
    if ((y == 0.0) || (a == 0.0))
    {
        if (b == 0.0)
        {
            ierr = 7;
            return;
        }
        else
        {
            w = 1.0;
            w1 = 0.0;
            return;
        }
    }

    // if test #4
    if (b == 0.0)
    {
        w = 0.0;
        w1 = 1.0;
        return;
    }


Administrator, 2008/10/19 23:19 Why can't I clean up the last if test block (test #4)? I am trying to faithfully follow the values returned by the original native library. If I tried to combine the last if block (test #4) with the first if block (test #1), many cases that should generate an ierr = 7 on return would not fail. The code would return ierr = 0 with w = 0 and w1 = 1. The final test for b == 0 cannot be short circuited without changing the behavior of the method on return. If I combined if statements #4 and #1 like the following code block illustrates, then data such as x = 1, y = 0, a = 0.5, b = 0 would not return ierr = 7. It might be possible to add one more clause to the if statement, but I'm tired and the code is "good enough" at this point to pass muster. If I think of a way around this in the future, I'll be sure to let update the code.

    // This change to the above code is tempting, but it
    // short circuits the ability to generate ierr = 7
    // return codes.
    // Combined if tests #1 and #4 from above
    if ((x == 0.0) || (b == 0.0))
    {
        if (a == 0.0)
        {
            ierr = 6;
            return;
        }
        else
        {
            w = 0.0;
            w1 = 1.0;
            return;
        }
    }
We have to go back to the notes I made in the second section of code in order to assure ourselves that the code path is correct. We are guaranteed that if b == 0, then a != 0 and vice versa. Since x + y = 1, we know that if x == 0, then y cannot be zero, with the reverse being true also.

Test patterns used:
x = 0, y = 1, a = 0, b = 0.5
x = 0, y = 1, a = 0.5, b = 0
x = 1, y = 0, a = 0, b = 0.5
x = 1, y = 0, a = 0.5, b = 0

The code does bring up an interesting issue. Should we continue to return an ierr for backward compatibility, or should the code raise execptions when input errors occur? As always, commments are welcome.

The next issue that needs to be addressed is comparison to zero. In a floating point environment, this is probably not healthy when the number is close to zero. We need to decide if a number is close enough to zero to be considered zero. That's a very long topic that I'm going to avoid until I am happy with the code layout.

ScrewTurn Wiki version 3.0.5.600. Some of the icons created by FamFamFam.