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.
--
Daniel Cannon
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
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
> So my question is this: How does one handle overflows
> such that they do *not* generate errors, but instead return
> the *actual* binary result?
Turn off integer overflow checks in the advanced compile options.
Mike
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.
--
Daniel Cannon
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
> Is there any way in VB to actually physically shift
> or manipulate a Double at the bit level?
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
> 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:
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.
--
Daniel Cannon
Cool! (I'm almost afraid to ask if you really meant VBA, not VB? <g>)
> They really should implement
> a bit-shift operator, though, and preferably one that can handle more
> than a Long! Thanks for your help.
Totally agree. Isn't gonna happen, though. It's a dead language; which isn't
altogether a Bad Thing.
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
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: ED...@mvps.org
WWW: Http://EDais.mvps.org/
¤ 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)
Which has *nothing* to do with the subject at hand, of course!
> Actually it was implemented in Visual Basic.NET 2003.
What a strange statement! Are you on something?
It's the Kool-Aid...
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.
--
Daniel Cannon
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.
> 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.
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.
--
Daniel Cannon
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
> I'm also not entirely sure how VB handles floating point integers--
That's an oxymoron, isn't it?
Heh, so you've met our resident evangelist! Repeat after me:
"Bite me, Paul!"
:-)
> never thought MS would invent a framework worse than MFC, but lo' and
> behold, they succeeded with .NET.
<g>
> 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.
The problem of theirs that just continues to grow -- they *are* their own best
competition.
From a performance point of view, this is a fastest way I've found in native VB of dealing with unsigned values.
> 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.
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.
> 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.
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.
> 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.
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.
An amazingly resilient meme, that one.
Since the product used to blunt the poison's taste in Jonestown was really Flav-or-ade.
>
>> I'm also not entirely sure how VB handles floating point integers--
>
> That's an oxymoron, isn't it?
Public fpi as Oxymoron
Yep, sure enough!
In VB-land, anything's possible :). I suppose I ought to have said
"floating point variables", but I assume you know what I meant =P.
--
Daniel Cannon
Rob
"Bob O`Bob" <filt...@yahoogroups.com> wrote in message
news:eJGDCt7V...@TK2MSFTNGP04.phx.gbl...
Hard to keep a Good Meme down! ;-)
I think one of the things that *most* confuses those new to VB is that the
definition of "Integer" is extremely precise. So much so, in fact, it hasn't
changed in over 30 years. So much so, it was invariate across 8-, 16-, and 32-bit
processors. In fact, it was this very confusion that led to the ultimate death of
VB, as we all knew and loved it. The newcomers couldn't be bothered to RTFM.
MSBASIC, 1976-2001, RIP.
¤ > ¤ 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.
¤
¤ Which has *nothing* to do with the subject at hand, of course!
Then why did you bring it up?
"Totally agree. Isn't gonna happen, though. It's a dead language; which isn't
altogether a Bad Thing."
¤
¤ > Actually it was implemented in Visual Basic.NET 2003.
¤
¤ What a strange statement! Are you on something?
¤
Why did you find it strange? Care to explain?
If I had to guess, I would say because this newsgroup is devoted to problems
people have with VB6 (and earlier). What other languages do (be they VB.NET,
C++, Fortran or whatever) doesn't go very far in answering questions posed
here by people using the programming language for which this newsgroup
caters to.
Rick
¤ > ¤ > Actually it was implemented in Visual Basic.NET 2003.
My post was in response to the statement about adding the feature to the language and correcting one
which claimed it would never happen.
It isn't up to me to decide whether the option is a viable alternative. I'm simply providing the
information for those who would choose to decide for themselves, and not having it forced upon them
by those who would never consider it.
Non sequitur.
It didn't happen. The language died. You're hallucinating. QED.
¤ > Well, I definitely don't need a shift operator that desperately :).
¤
¤ Heh, so you've met our resident evangelist! Repeat after me:
¤
¤ "Bite me, Paul!"
¤
¤ :-)
Hey, someone's gotta save the folks from the resident anti-Microsoft boogeymen. ;-)
> My post was in response to the statement about
> adding the feature to the language
But the feature you were taking about, as I recall, was a Shift or perhaps a
Rotate instruction. Such a feature has *not* been added to Visual Basic, at
least not to the *real* Visual Basic. Dotnet is effectively a completely
different language. It is *not* an update to VB6. You must be "on something"
if you think that it is. Micro$haft can of course call it anything they
like, just as you can spend all year if you wish, or even longer, calling a
spade a fork. But calling a spade a fork will not actually turn it into a
fork, no matter how many times you say it!
Mike