Home
Search
 
What's New
Index
Books
Links
Q & A
Newsletter
Banners
 
Feedback
Tip Jar
 
C# Helper...
 
XML RSS Feed
Follow VBHelper on Twitter
 
 
 
MSDN Visual Basic Community
 
 
 
 
TitleX \ COL_WID
Keywordsquick question answer, quiz answer, answer
Categories
 
1. Why don't the calculated row and col values match the original values?

    The intent of the code is to perform integer division of the value X by COL_WID. In other words, to divide X by COL_WID and the truncate the result to get an integer row number.

    However, the \ operator only works with integer operands. Before performing the calculation, Visual Basic converts both of the operands X and COL_WID into integer types (actually Longs). At this point in the code, X = 8.75 and COL_WID = 1.25 so they convert into the Long values 9 and 1. Clearly 9 \ 1 = 9 so the Debug statement prints 9.

    Similarly when it calculates Y \ ROW_HGT Visual Basic converts Y = 7.5 into 8 and ROW_HGT = 2.5 into 2. Then Y \ ROW_HGT = 4.

2. Compare the data type "promotion" performed by Visual Basic in the following two statements:

  X = col * COL_WID
  Debug.Print col & " = " & X \ COL_WID

    Normally when performing a calculation involving more than one data type, Visual Basic promotes the lower resolution data type into the higher one. For example, when you multiply an Integer with a Single, Visual Basic promotes the Integer to a Single before multiplying. Similarly if you multiply a Single and a Double, Visual Basic promotes the Single to a Double.

    When it finishes performing the calculation, the program "demotes" the result if necessary to store it in a variable of lower precision. For example, in the following code the system promotes the 2 to a Double (1.5 is a Double), calculates the resulting Double value 3.0, and then demotes this value to store it in the Integer variable i.

        Dim i As Integer
    

    i = 2 * 1.5

    The first line of code X = col * COL_WID works in this normal way. Variable col is an Integer but COL_WID is a Double so Visual Basic promotes col to a Double. The resulting Double is demoted to fit in the Single variable X.

    Note, however, that some operations force promotion or even demotion. The code 1 / 3 promotes the 1 and 3 to Doubles before performing floating point division. However, if the operands are already floating point values, Visual Basic does not promote them. For example, in the expression 1! / 3! the 1 and 3 are stored as Singles (that's what the ! means) so they are already floating point numbers. They don't need to be promoted before performing floating point division so the result is Single not Double as you might expect.

    Now back to the question at hand. The second line of code Debug.Print col & " = " & X \ COL_WID works backwards. It sees the \ operator so it demotes the variables X and COL_WID to Longs before performing its calculation. The result is a Long.

    The moral is to use \ only when both operands are integers and you want an integer result.

3. What are the correct Debug.Print statements?

    To get the correct result, you need to perform floating point division and then truncate the result.

        Debug.Print col & " = " & Int(X / COL_WID)
        Debug.Print row & " = " & Int(Y / ROW_HGT)

    Note that this gives a different result if you use CInt instead of Int. Note also that floating point division / takes a bit longer than integer division \ so there is some reason to use \ when you are working with integer values and you want an integer result.

 
' See if X > 7 and user_name is not blank.
If (X > 7) And (Len(user_name) > 0) Then
    ' Do something ...
End If
 

    This code is easier to read and understand. It uses Boolean operations to combine Boolean values. It doesn't assume that False is 0 and True is non-zero.

    The original tip was proposed because it is faster than using Boolean operators. In an informal test, the tricky solution took about 0.000000264 seconds while the improved version took only 0.000000308 seconds. There is some difference but not enough to justify this confusing code.


    Graham Cottle points out:

    Surely if using .Net the speed will be improved if you use the AndAlso construct?

        ' See if X > 7 and user_name is not blank.
        If (X > 7) AndAlso (Len(user_name) > 0) Then
            ' Do something ...
        End If

    Thus the Len(user_name) > 0 is not evaluated if X <= 7 as that part is already false.

    Put the one most likely to be false first in the construct.


    This is absolutely true because AndAlso provides "short circuit" evaluation. It doesn't evaluate the second expression if it knows from the first that the combined statement must be false. This is different from the And operator which evaluates both expressions whether they are true or not. Visual Basic 6 and earlier only support And. Other languages use short circuit evaluation.

    Using AndAlso changes the way Visual Basic handles functional side effects. For example, consider this code:

        If Function1() And Function2() Then
            ...
        End If

    In this case, both Function1 and Function2 are executed. If these routines have side effects (e.g. they modify global variables), you need to pay extra attention. If you use AndAlso instead of And, Function2 may not execute so its side effects will not occur.

    Of course writing functions with side effects is poor programming practice because it can be very confusing so this should not be an issue. The original developers of Visual Basic felt people would be confused if they used short circuit evaluation and their side effects didn't occur so they made And evaluate all arguments.


    Toby adds:

    Perhaps faster way would be

        If X > 7 Then
            If Len(User_name) > 0 Then
                ...
            End If
        End If

    The second function will not be checked if the first is true. With AND/OR operation both functions are tested whether the first result. This should be changed in VB.NET but it happened same way as Boolean values.

    [This is also true and shows how you can avoid the extra test in Visual Basic 6 and earlier versions.

    Toby points out that this can save a lot of time if the tests are slow, for example, if you invoke functions that use database lookups and comparisons.

    Rod]

Moral

Get it working correctly first. Then optimize only where you know it is necessary. (This is an important theme in my book Bug Proofing Visual Basic).

Most software projects fail because they don't work correctly, not because they are too slow.

Copyright © 1997-2010 Rocky Mountain Computer Consulting, Inc.   All rights reserved.
  Updated