efficiency question.

There are various mechanisms for evaluating a decision tree in vb. e.g If .. else if .., Select case, etc. Aside from programming convenience is there any effeciency difference between these options or do they all compile down to the same low level code, leaving aside the issue of whether or not all test expressions are evaluated


Answer this question

efficiency question.

  • Jkat98

    Im having some trouble with Case is, The select case is only comparing the first sentence.

    dim var as integer = 2
    Select Case Var

    case is > 1

    Price.text ="1"
    Case 2
    Price.Text = "50"
    Case 3
    Price.Text = "60"

    Case Else
    Price.Text = "0"

    End Select

    in this example only "Case is > 1" is executed. Can you tellme why


  • linzbfc

    hgen_banks wrote:
    I am not sure where some of you are getting your information about the If/ElseIf construct, but it certainly does NOT evaluate every condition. Both the If/ElseIf and the Select Case only execute until the first true condition. The Select can be more efficient if certain cases, such as selecting values from an enum with values in ascending numerical order starting with 0. The IL generated by such a Select statement is quite a bit different that using If x = 0 ... elseif x = 1 ... etc. Also, the Select statement can be more efficient because it only needs to evaluate the argument once. However, the main reason to do a Select instead of If is for readability. As noted by one of the other responses, the difference in efficiency will be unnoticeable unless the logic is being run thousands upon thousands of times.

    Hi hgen_banks,

    If you write two separate If Then blocks they are evaluated separately right

    Code Snippet

    If whatever=2 Then

    'Do something

    End If

    Code Snippet

    If something=3 Then

    'Do something else

    End If

    I will have to trace sometime a full If Then ElseIf EndIf block as i thought ( or I was led to believe )

    that ElseIf is like writing a 2nd full If Then End If block.

    You might like to check it for yourself too

    I would love to see the Intermediate Language code as assembly language, if what you say is true.

    Regards,

    S_DS



  • JGP

    Yes, two completely separate if blocks will have both conditions evaluated. However, the discussion was about If/ElseIf/End If. Here's an example with the IL shown by Reflector.

    If (Me.hr > 12) Then
    tempHr = (Me.hr - 12)
    ampm
    = " PM"
    Else
    If (Me.hr = 12) Then
    tempHr
    = 12
    ampm = " PM"
    ElseIf (Me.hr = 0) Then
    tempHr
    = 12
    ampm = " AM"
    Else

    tempHr = Me.hr
    ampm
    = " AM"
    End If

    And now the IL. Beware, it is kind of long, but if you look through it, you will see that it does indeed stop after finding the first condition that is true.

    L_0000: ldarg.0
    L_0001: ldfld int32 GaimLogViewer.Time::hr
    L_0006: ldc.i4.s 12
    L_0008: ble.s L_001c
    L_000a: ldarg.0
    L_000b: ldfld int32 GaimLogViewer.Time::hr
    L_0010: ldc.i4.s 12
    L_0012: sub.ovf
    L_0013: stloc.1
    L_0014: ldstr " PM"
    L_0019: stloc.0
    L_001a: br.s L_0052
    L_001c: ldarg.0
    L_001d: ldfld int32 GaimLogViewer.Time::hr
    L_0022: ldc.i4.s 12
    L_0024: bne.un.s L_0031
    L_0026: ldc.i4.s 12
    L_0028: stloc.1
    L_0029: ldstr " PM"
    L_002e: stloc.0
    L_002f: br.s L_0052
    L_0031: ldarg.0
    L_0032: ldfld int32 GaimLogViewer.Time::hr
    L_0037: ldc.i4.0
    L_0038: bne.un.s L_0045
    L_003a: ldc.i4.s 12
    L_003c: stloc.1
    L_003d: ldstr " AM"
    L_0042: stloc.0
    L_0043: br.s L_0052
    L_0045: ldarg.0
    L_0046: ldfld int32 GaimLogViewer.Time::hr
    L_004b: stloc.1
    L_004c: ldstr " AM"
    L_0051: stloc.0
    L_0052: ldc.i4.6

  • FredV

    If you are doing the decision a few hundred times, then it probably doesn't matter. Depends upon your definition of efficiency :) Smallest amount of code, or fastest

    Personally, with the mega-booger-flipflops (sic) that processors have today, the efficiency comes in writing readable code; any bug introduced could negate any speed gains you may get for the next 50 years...

    They don't compile to the same code, of course. But there's more to the 'speed' issue (and amount of code), beyond simply choosing between select case and an if/then (e.g. calling math.sqrt() is probably going to add way more code than even the longest branch).



  • Brent1

    Javier Parra wrote:
    Im having some trouble with Case is, The select case is only comparing the first sentence.

    dim var as integer = 2
    Select Case Var

    case is > 1

    Price.text ="1"
    Case 2
    Price.Text = "50"
    Case 3
    Price.Text = "60"

    Case Else
    Price.Text = "0"

    End Select

    in this example only "Case is > 1" is executed. Can you tellme why

    Hi,

    Yes you set var=2.

    as the 1st statement is TRUE that is 2 IS greater than 1 so only the 1st statement runs.

    Use IF then statements if you want more than one test to be evaluated as True

    If var > 1 then

    Price.Text ="1"

    ElseIf var = 2 then

    Price.Text="50"

    ElseIf var= 3 then price.text="60"

    Else

    Price.text="0"

    EndIf

    var would need to be less less than 1 for price.text to become = "0"

    Regards,

    S_DS



  • My Vizai

    I am not sure where some of you are getting your information about the If/ElseIf construct, but it certainly does NOT evaluate every condition. Both the If/ElseIf and the Select Case only execute until the first true condition. The Select can be more efficient if certain cases, such as selecting values from an enum with values in ascending numerical order starting with 0. The IL generated by such a Select statement is quite a bit different that using If x = 0 ... elseif x = 1 ... etc. Also, the Select statement can be more efficient because it only needs to evaluate the argument once. However, the main reason to do a Select instead of If is for readability. As noted by one of the other responses, the difference in efficiency will be unnoticeable unless the logic is being run thousands upon thousands of times.

  • Joel Martinez

    I think select case is more efficient.... especially when you code probablistically ordering the most likely cases at the top.



  • fbiots

    It looks like you are pretty close to reading the IL right. Let's break this down a little and just look at the first branch:

    If (Me.hr > 12) Then
    tempHr = (Me.hr - 12)
    ampm
    = " PM"

    Now, the corresponding IL with some comments to explain what's going on:


    L_0000: ldarg.0 //load the Me pointer on the stack
    L_0001: ldfld int32 GaimLogViewer.Time::hr //use the Me pointer to put the hr field on the stack
    L_0006: ldc.i4.s 12 //push the constant number 12 on the stack
    L_0008: ble.s L_001c //if Me.hr <= 12 goto L_001c otherwise continue at the next instruction
    L_000a: ldarg.0
    L_000b: ldfld int32 GaimLogViewer.Time::hr
    L_0010: ldc.i4.s 12
    L_0012: sub.ovf
    L_0013: stloc.1
    L_0014: ldstr " PM"
    L_0019: stloc.0
    L_001a: br.s L_0052 //end of branch, go to end of If/ElseIf block

    So, you can see that if the original condition (Me.hr > 12) is true, the code corresponding to that block gets run followed by a jump to the end of the If block. If the condition is not true, the program jumps to the next condition (at L_001c) and evaluates that condition.

    To see the IL output of a program you write, get a program like Reflector, the one I used here, (search the internet for .NET Reflector and see what you find) or ILDASM (which I have never used myself).

  • meighlough

    The biggest difference in the "Select Case" and the "If/then" contructs is that every "If" or "Else If" line in an "If" statement is evaluated...However in the "Select Case" statement the "case" is only evaluated until the first true "case" is found and then the Select Case is exited...

    So the efficency of the "Select Case" when comparing to the "If" also depends on how you set up the select case...



    Dim
    Z As Boolean = True

    Dim A As Boolean = False

    Dim B As Boolean = False

    Dim C As Boolean = False

    Select Case True

    Case Z

    ' do something Z

    Case A

    ' do something A

    Case B

    ' do something B

    Case C

    ' do something C

    End Select

    If Z Then

    ' do something Z

    ElseIf A Then

    ' do something A

    ElseIf B Then

    ' do something B

    ElseIf C Then

    ' do something C

    End If

    in that example the only case that is evaluated is Case Z, however each if and else if is evaluated although only 'Do Something Z' is executed

    This contruct is also very important to realize when using a select case on numeric values:


    Dim I As Integer = 100

    Select Case i

    Case Is < 1000
    'Do1000

    Case Is = 100
    'Do100

    Case Is > 99
    'Do99

    End Select

    all three cases evaluate to true however only Case is <1000 is evaluated and only the 'Do 1000' is executed



  • IamHuM

     

    Hi,

     I'd have to agree with ReneeC about SELECT CASE being more efficient but only when it is doing

    simple comparisons such as

    Dim myVar As Integer

    Select myVar

     Case 1

    ' some code

     Case 2

    ' some code

     Case 3

    ' some code

     Case 4

    ' some code

     Case 5

    ' some code

    End Select

    However when ranges are put in the code is still doing more comparisons as in complex IF....THEN constructs so at the end of the day it depends on your code i guess.

    See the example at the end of this next part ( please maximise you window to use the inner scrollbar ) .>>

    Select...Case Statements

    Executes one of several groups of statements, depending on the value of an expression.

    Select [ Case ] testexpression
      [ Case expressionlist
       [ statements ] ]
      [ Case Else
       [ elsestatements ] ]
    End Select

    Parts

    testexpression
    Required. Expression. Must evaluate to one of the elementary data types (Boolean, Byte, Char, Date, Double, Decimal, Integer, Long, Object, Short, Single, and String).
    expressionlist
    Required in a Case statement. List of expression clauses representing match values for testexpression. Multiple expression clauses are separated by commas. Each clause can take one of the following forms:
    • expression1 To expression2
    • [ Is ] comparisonoperator expression
    • expression

    Use the To keyword to specify the boundaries of a range of match values for testexpression. The value of expression1 must be less than or equal to the value of expression2.

    Use the Is keyword with a comparison operator (=, <>, <, <=, >, or >=) to specify a restriction on the match values for testexpression. If the Is keyword is not supplied, it is automatically inserted before comparisonoperator.

    The form specifying only expression is treated as a special case of the Is form where comparisonoperator is the equal sign (=). This form is evaluated as testexpression = expression.

    The expressions in expressionlist can be of any data type, provided they are implicitly convertible to the type of testexpression and the appropriate comparisonoperator is valid for the two types it is being used with.

    statements
    Optional. One or more statements following Case that are executed if testexpression matches any clause in expressionlist.
    elsestatements
    Optional. One or more statements following Case Else that are executed if testexpression does not match any clause in the expressionlist of any of the Case statements.
    End Select
    Terminates Select...Case block.

    Remarks

    If testexpression matches any Case expressionlist clause, the statements following that Case statement are executed up to the next Case statement or the End Select statement. Control then passes to the statement following End Select. If testexpression matches an expressionlist clause in more than one Case clause, only the statements following the first match are executed.

    The Case Else statement is used to introduce the elsestatements to be executed if no match is found between the testexpression and an expressionlist clause in any of the other Case statements. Although not required, it is a good idea to have a Case Else statement in your Select Case block to handle unforeseen testexpression values. If no Case expressionlist clause matches testexpression and there is no Case Else statement, execution continues at the statement following End Select.

    You can use multiple expressions or ranges in each Case clause. For example, the following line is valid:

    Case 1 To 4, 7 To 9, 11, 13, Is > MaxNumber
    Note   The Is keyword used in the Case and Case Else statements is not the same as the Is comparison operator.

    You also can specify ranges and multiple expressions for character strings. In the following example, Case matches strings that are exactly equal to "apples", strings with values between "nuts" and "soup" in alphabetical order, and the current value of TestItem:

    Case "apples", "nuts" To "soup", TestItem

    The setting of Option Compare can affect string comparisons. Under Option Compare Text, the strings "Apples" and "apples" compare as equal, but under Option Compare Binary, they do not.

    Select Case statements can be nested. Each nested Select Case statement must have a matching End Select statement.

    If you do not need to execute any more of the statements in a Case or Case Else statement block, you can exit the block by using the Exit Select statement. This transfers control immediately to the statement following End Select.

    Example

    This example uses the Select Case statements to write a line corresponding to the value of the variable Number. The second Case statement contains the value that matches the current value of Number, so the statement that writes "Between 6 and 8" is executed.

    Dim Number As Integer = 8
    ' ...
    Select Number  ' Evaluate Number.
      Case 1 To 5  ' Number between 1 and 5, inclusive.
       Debug.WriteLine("Between 1 and 5")
      ' The following is the only Case clause that evaluates to True.
      Case 6, 7, 8  ' Number between 6 and 8.
       Debug.WriteLine("Between 6 and 8")
      Case 9 To 10  ' Number is 9 or 10.
       Debug.WriteLine("Greater than 8")
      Case Else  ' Other values.
       Debug.WriteLine("Not between 1 and 10")
    End Select

     

    Regards,

    S_DS

     

     



  • Apollo13

    unless I'm mistaken I believe the compiler changes most if statements to Selects when it does its thing so I would say that the select case is the best as well.

  • golfdude54

    hgen_banks wrote:
    Yes, two completely separate if blocks will have both conditions evaluated. However, the discussion was about If/ElseIf/End If. Here's an example with the IL shown by Reflector.

    If (Me.hr > 12) Then
    tempHr = (Me.hr - 12)
    ampm
    = " PM"
    Else
    If (Me.hr = 12) Then
    tempHr
    = 12
    ampm = " PM"
    ElseIf (Me.hr = 0) Then
    tempHr
    = 12
    ampm = " AM"
    Else

    tempHr = Me.hr
    ampm
    = " AM"
    End If

    And now the IL. Beware, it is kind of long, but if you look through it, you will see that it does indeed stop after finding the first condition that is true.

    L_0000: ldarg.0
    L_0001: ldfld int32 GaimLogViewer.Time::hr
    L_0006: ldc.i4.s 12
    L_0008: ble.s L_001c
    L_000a: ldarg.0
    L_000b: ldfld int32 GaimLogViewer.Time::hr
    L_0010: ldc.i4.s 12
    L_0012: sub.ovf
    L_0013: stloc.1
    L_0014: ldstr " PM"
    L_0019: stloc.0
    L_001a: br.s L_0052
    L_001c: ldarg.0
    L_001d: ldfld int32 GaimLogViewer.Time::hr
    L_0022: ldc.i4.s 12
    L_0024: bne.un.s L_0031
    L_0026: ldc.i4.s 12
    L_0028: stloc.1
    L_0029: ldstr " PM"
    L_002e: stloc.0
    L_002f: br.s L_0052
    L_0031: ldarg.0
    L_0032: ldfld int32 GaimLogViewer.Time::hr
    L_0037: ldc.i4.0
    L_0038: bne.un.s L_0045
    L_003a: ldc.i4.s 12
    L_003c: stloc.1
    L_003d: ldstr " AM"
    L_0042: stloc.0
    L_0043: br.s L_0052
    L_0045: ldarg.0
    L_0046: ldfld int32 GaimLogViewer.Time::hr
    L_004b: stloc.1
    L_004c: ldstr " AM"
    L_0051: stloc.0
    L_0052: ldc.i4.6

    The 3 lots of br.s L_0052 BRanch to the end.

    The 3 other tests still Branch to the other tests as far as I read the IL, or am I wrong

    BLE = Branch if Less than or Equal ( as far as I know ),

    BNE = Branch if Not Equal ( as far as I know ).

    Can you detail how you got the IL code up please

    Regards,

    S_DS



  • efficiency question.