Overflowing a Long

Discussion in 'AutoCAD' started by AmiDaniel, Feb 22, 2007.

  1. AmiDaniel

    AmiDaniel Guest

    Hi all,

    I've yet again found myself baffled by how complicated VB makes
    relatively simple tasks, and I was hoping someone might be able to
    shed some light on a solution to my problem.

    My problem can be simplified to the following: if I have a Long
    integer that has reached its maximum capacity (2^31-1), and I add one
    to this Long, VB throws an Overflow error. What I would like to happen
    (in the context of my current appliation, which is uniquely hashing
    Strings), however, is for the result of evaluating 2 ^ 31 and storing
    it to a long to _rollover_, to become the actual result of the binary
    arithmetic, namely -2 ^ 31. In most languages, this is done
    automatically. For instance, if you have a byte that is maxed out:

    2 ^ 8 = 255 = 11111111

    And you add 1:

    11111111
    + 00000001
    ----------------
    1 00000000

    The result is 0 (the minimum value), as the ninth bit does not fit in
    the buffer of the Byte and so is discarded. With a Long integer, the
    64th bit is the sign bit, so when you add 1, it becomes 100...00, or
    the smallest possible value that can fit in that buffer (-2 ^ 31), and
    when you add 1 to -1 (111...111), the buffer overflows leaving only
    zeros. **This is the math that VB is doing under the hood**, but
    instead of returning the result, it does a second check to make sure
    that after discarding these extra bits, the result is 0 (the only
    overflow case VB allows), and, if it's not, it throws an error. So my
    question is this: How does one handle overflows such that they do
    *not* generate errors, but instead return the *actual* binary result?

    I've tried various algorithms, one of which works but is painfully
    slow (by recursively converting a double back down into a long).
    Visual Basic's bitwise operators (And, Or, Xor -- they don't even have
    a LR shift) support at most comparisons between two 32-bit types (Long
    And Long = Long); however, in order to make use of those in this case,
    I would need to compare two 64 bit-types (Double And Double = Double),
    as I need to compress the result of my arithmetic back down into an
    overflowed Long. Is there any way in VB to actually physically shift
    or manipulate a Double at the bit level?

    Ultimately, what work best would be the VB equivalent of the following
    Java method--I cannot however find a way to do this in VB unless I can
    find a method to shift the bits of a Double in a relatively efficient
    manner. Note that, in Java, an "int" is a 32-bit signed integer (the
    equivalent of a VB Long) and a "long" is a 64-bit signed integer (the
    equivalent of a VB Double, minus the floating point).

    import java.util.Random;

    public class BinMath {
    public static void main(String[] args) {
    Random r = new Random(7);
    int val = 0;
    for (int i = 0; i < 20; i ++) {
    long d = r.nextLong();
    val += handleOverflow(val + d);
    }
    System.out.printf("Final: %d\n", val);
    }

    public static int handleOverflow(long d) {
    System.out.printf("%d -> ", d);
    while (d > Integer.MAX_VALUE || d < Integer.MIN_VALUE) {
    d = d >> 32;
    }
    System.out.printf("%d\n", d);

    return (int) d;
    }
    }

    Any ideas how to do this in VB???? Thanks in advance.
     
    AmiDaniel, Feb 22, 2007
    #1
  2. Cutting to the chase, one potential solution would be to turn off Overflow Checking
    in the Advanced Compiler Optimizations. That'll make debugging a little more
    difficult as that really only kicks in when running the EXE, I believe, so you'd
    need to test your boundary conditions outside the IDE.

    You can also do this algorithmically, but the overhead would be far greater if the
    above does the trick.
    --
    ..NET: It's About Trust!
    http://vfred.mvps.org



     
    Karl E. Peterson, Feb 22, 2007
    #2
  3. AmiDaniel

    Michael C Guest

    Simple solution to that is to compile the appropriate code into a dll. You
    could even make it look like the java function:

    java: val += handleOverflow(val + d); (is this correct?)
    vb: handleOverflow(val, d);

    For the OP, C# does the rollover but I'm not sure about vb.net.

    Michael
     
    Michael C, Feb 22, 2007
    #3
  4. Turn off integer overflow checks in the advanced compile options.

    Mike
     
    Mike Williams, Feb 22, 2007
    #4
  5. AmiDaniel

    AmiDaniel Guest

    Oh, wow, there's a compiler option to supress overflow checking?
    Great, I'll give that a try and see if it works--if it does, I take
    back the nasty things I said about VB :). They really should implement
    a bit-shift operator, though, and preferably one that can handle more
    than a Long! Thanks for your help.
     
    AmiDaniel, Feb 22, 2007
    #5
  6. I agree that VB is extremely limited in that area, but you can perform some
    simple jobs fairly easily and quickly. Multiply by 2 will shift the bits
    left for you, and divide by 2 (using integer division \ rather than standard
    division / for speed) will shift them right. That, coupled with turning off
    integer overflow checks in the compile options, will allow to do some
    things, with certain limitations. VB does generally suck though when it
    comes to dealing with data at bit level.

    Mike
     
    Mike Williams, Feb 22, 2007
    #6
  7. AmiDaniel

    Michael C Guest

    I just realised this is VBA for autocad which probably doesn't have compile
    options at all. Daniel, download this dll to your machine and add it as a
    reference to your project:

    http://mikesdriveway.com/misc/OverflowStuffLib.zip

    Then you can write code like this:

    x = AddLongs(x, 1)
    x = SubtractLongs(x, 1)

    You might need the vb6 runtimes which can be downloaded from MS.

    Michael
     
    Michael C, Feb 22, 2007
    #7
  8. AmiDaniel

    AmiDaniel Guest

    Actually, this is being built as an ActiveX dll, so I can specify
    compile options--I simply cross-posted as I wasn't sure where I was
    going to get the best answer :D. I will take a look at your library
    though, as it may still come in handy if I ever need to do this
    outside of a compiled app. Thanks again.
     
    AmiDaniel, Feb 22, 2007
    #8
  9. Totally agree. Isn't gonna happen, though. It's a dead language; which isn't
    altogether a Bad Thing.
     
    Karl E. Peterson, Feb 22, 2007
    #9
  10. AmiDaniel

    Michael C Guest

    Here's the extensive source code. ByVal is used because it is faster I
    believe. It would possibly be better to put this into a dll instead of
    turning off the integer checks throughout your app but as you said, most
    languages don't have this check anyway and the world hasn't imploded.

    Public Function AddLongs(ByVal Value1 As Long, ByVal Value2 As Long) As Long
    AddLongs = Value1 + Value2
    End Function

    Public Function SubtractLongs(ByVal Value1 As Long, ByVal Value2 As Long) As
    Long
    SubtractLongs = Value1 - Value2
    End Function

    Michael
     
    Michael C, Feb 22, 2007
    #10
  11. I've yet again found myself baffled by how complicated VB makes
    <snip>

    Have a look at this old post for an example of how to work with QWords in VB:
    http://groups.google.co.uk/group/microsoft.public.vb.general.discussion/msg/647fea5d3bcb6ce0
    It also deals with a low unsigned DWord in this code should you not want the full 64-bit range, in that case all you'd
    need is something like:

    '***
    Private Function AddDWordsUnsigned(ByVal inA As Long, ByVal inB As Long) As Long
    AddDWordsUnsigned = UDWordToSDWord(SDWordToUDWord(inA) + inB)
    End Function
    '***

    This version silently ignores overflow past the 32'nd bit should it occur. If you're doing lots of additions to this
    value, then I would suggest using a Currency type throughout and only converting back to an unsigned DWord at the end.
    Also, should you need it in the future, bit-shifting can be emulated in VB by multiplying or integer dividing by powers
    of 2 i.e. Multiply by 2 == <<1, divide by 4 == >>2 etc.
    Hope this helps,

    Mike


    - Microsoft Visual Basic MVP -
    E-Mail:
    WWW: Http://EDais.mvps.org/
     
    Mike D Sutton, Feb 23, 2007
    #11
  12. AmiDaniel

    Paul Clement Guest

    ¤ Oh, wow, there's a compiler option to supress overflow checking?
    ¤ Great, I'll give that a try and see if it works--if it does, I take
    ¤ back the nasty things I said about VB :). They really should implement
    ¤ a bit-shift operator, though, and preferably one that can handle more
    ¤ than a Long! Thanks for your help.

    Actually it was implemented in Visual Basic.NET 2003.


    Paul
    ~~~~
    Microsoft MVP (Visual Basic)
     
    Paul Clement, Feb 23, 2007
    #12
  13. Which has *nothing* to do with the subject at hand, of course!
     
    Karl E. Peterson, Feb 23, 2007
    #13
  14. What a strange statement! Are you on something?
     
    Mike Williams, Feb 23, 2007
    #14
  15. It's the Kool-Aid...
     
    Karl E. Peterson, Feb 23, 2007
    #15
  16. AmiDaniel

    AmiDaniel Guest

    Well, I definitely don't need a shift operator that desperately :). I
    never thought MS would invent a framework worse than MFC, but lo' and
    behold, they succeeded with .NET.

    What would be ideal would be if MS would simply opensource their VB6
    compiler and let independents pound it into something that works
    better--but that's obviously not going to happen... I guess I'll just
    have to learn to work with what I've got.
     
    AmiDaniel, Feb 23, 2007
    #16
  17. AmiDaniel

    AmiDaniel Guest

    Hmm, looks interesting. Changing the compiler options seemed to solve
    my problem, so I'll likely won't need that for this app, but thanks
    anyway--it may well come in handy later. It takes an approach that I
    probably would have never thought of, and it's far more efficient
    (although requiring more space and type conversions) than my old
    recursive method to compress doubles.
    Again, I am slighltly concerned about the efficiency of this. Shift
    left by x bits requires calculating the exponent of 2^x (and exponent
    operations tend to be slow in all languages) and then performing the
    actual multiplication, which is quite a bit slower than the single
    operation of shifting bits. This may seem like nit-picking, but in my
    current app, I'd be performing this bit-shifting an average of about
    10 times on a little more than 2 million items. It adds up.

    I'm also not entirely sure how VB handles floating point integers--
    does multiplying, i.e., " 123.003582382101" actually shift the
    physical bits of the float? I don't believe so. Similarly, if you
    divide 3 by 2 and store it in a float, it won't be 1 (the actual shift
    right), but rather 1.5. I worry that if I use multiplication/division,
    even I think I'll never use any types that are floating point, I'll
    wind up digging myself a very deep grave that I wouldn't have to worry
    about if I had an actual shift operator.
     
    AmiDaniel, Feb 23, 2007
    #17
  18. In cases like that, it really pays off to precalculate a little lookup table for the
    powers:

    Private Function TwoToThe(ByVal Power As Long) As Long
    Static BeenHere As Boolean
    Static Results(0 To 31) As Long
    Dim i As Long

    ' Build lookup table, first time through.
    ' Results hold powers of two from 0-31.
    If Not BeenHere Then
    Results(0) = 1
    For i = 1 To 30
    Results(i) = Results(i - 1) * 2
    Next i
    Results(31) = &H80000000
    BeenHere = True
    End If

    ' Return requested result
    If Power >= 0 And Power <= 31 Then
    TwoToThe = Results(Power)
    End If
    End Function
    That's an oxymoron, isn't it?
     
    Karl E. Peterson, Feb 23, 2007
    #18
  19. Heh, so you've met our resident evangelist! Repeat after me:

    "Bite me, Paul!"

    :)
    The problem of theirs that just continues to grow -- they *are* their own best
    competition.
     
    Karl E. Peterson, Feb 23, 2007
    #19
  20. Hmm, looks interesting. Changing the compiler options seemed to solve
    From a performance point of view, this is a fastest way I've found in native VB of dealing with unsigned values.
    In the majority of cases you already know how many bits you want to shift by and as such can simply put in the
    pre-calculated value rather than using the costly power operator. In these cases you get very fast code, it may even be
    optimised by the compiler into a SHL/SHR operation in the compiled .EXE.
    Shift operations are bitwise and only ever operate on integer values though?.. Due to the way floating point values are
    stored, a bitwise operation simply makes no sense there.
    The Currency data-type in VB is a _fixed_-point rather than floating point value, which means that it's really stored as
    an integer behind the scenes which makes it more accurate to do these kind of operations with than floating point types
    such as a Double or Decimal.
    VB has two division methods; "/" performs floating point division, while "\" performs much faster integer division which
    circumvents this problem. The overhead of calling out to a DLL every time a bit-shift needs to be performed is likely
    going to be higher than jumping through a few hoops in VB. If you're really worried about performance then personally I
    would move the entire hashing algorithm into a C++ DLL and just make one call in the VB app to that, but it does give
    you an extra dependency to cart around.
    Hope this helps,

    Mike


    - Microsoft Visual Basic MVP -
    E-Mail:
    WWW: Http://EDais.mvps.org/
     
    Mike D Sutton, Feb 23, 2007
    #20
Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.