Forum Discussion
Mike_Thompson_9
Nimbostratus
Aug 08, 2007CommonULong64 OverflowException
I am trying to convert the CommonULong64 type to UInt64 in .NET for a CommonStatistic type. Sometimes this works fine and I get a good number back. Other times I get a System.OverflowException. The CommonULong64 value going in has a high of 4 and a low of -176378626 which does not look right, but that is what is coming back from the SOAP call. Here is my converstion function:
Public Shared Function Build64(ByVal value As Object) As UInt64
Return Convert.ToUInt64(value.high << 32 Or value.low)
End Function
Any ideas?
20 Replies
- Ahh, the fun that is VB...
First, yes, those values you have (4, and -176378626) are valid. We use signed types because of java's limitations with support for unsigned types.
You have the correct algorighm (high << 32 | low) but the issue is with VB's builtin types being 32 bits. So, when you have a high large number for your high value, the first shift-left of 32 bits results in an overflow since the default size is 32 bits. I don't believe you can cast a 32 bit value to a 64 bit value like you can with C so when I tinkered around with this, I had to create new 64 bit types and assign them manually. This should work for you:Public Function Build64(ByVal value As Object) As UInt64 Dim ui64High As UInt64 = value.high Dim ui64Low As UInt64 = value.low ui64High = ui64High << 32 Return Convert.ToUInt64(ui64High Or ui64Low) End Function
There may be a way to condense this but since I'm by no means a VB guru, this is the best I could come up with. I did verify that the outcome of this function is the same as it's C counterpart:public UInt64 build64(CommonULong64 ul64) { return (((UInt64)(UInt32)ul64.high) << 32) | ((UInt64)(UInt32)ul64.low); }
Hope this helps...
-Joe - Mike_Thompson_9
Nimbostratus
Thanks Joe, but I am still getting the same results. In other words, I am still getting the OverflowException. I used both the function you provided and the condensed version below (both with the same results):Public Shared Function Build64(ByVal value As Object) As UInt64 Return Convert.ToUInt64((Convert.ToUInt64(value.high) << 32) Or Convert.ToUInt64(value.low)) End Function
I will keep researching, but any other ideas? - Mike_Thompson_9
Nimbostratus
I did figure out this:
Type going in {LocalLB.Pool.CommonULong64}Object
high4 Long
low-1471517967Long
(Convert.ToUInt64(value.high) << 32) = 17179869184ULong
Convert.ToUInt64(value.low) = Run-time exception thrown : System.OverflowException - Value was either too large or too small for a UInt64.
.... - Mike_Thompson_9
Nimbostratus
There appears to be a problem with the large negative number on the [value.low]. From doing some research, the best method is to turn the negative number in to a positive number, then do the calculation. From what I can tell, this works:Public Shared Function Build64(ByVal value As Object) As UInt64 Return Convert.ToUInt64((Convert.ToUInt64(value.high) << 32) Or Convert.ToUInt64(Math.Abs(value.low))) End Function
I am getting a good number back, but I am not 100% sure it is correct. However the exception is gone. Your thoughts? - Andy_Herrman_22
Nimbostratus
I worry your low value will be wrong using ABS.
I think the problem when you don't use ABS is that when you convert value.low (a 32 bit integer I beleve) to a 64 bit integer it fills in all the new bits with a 1. I forget the terms, but there are two ways of doing a right shift. One fills in the values on the left with a 0, the other with whatever the leftmost bit started as. So, looking at a small example:
Using 0s: 11010010 >> 2 = 00110100
Extending last bit: 11010010 >> 11110100
The second one (extending) tends to be the default as it preserves the mathematical operation of << and >> being equivalent to multiplying and dividing by 2.
When you case to a larger size integer it essentially does this kind of shift. Since you're starting with a negative number it's filling in the new bits with a 1. So what you really want to do is mask the new number. I don't know the VB syntax, but I'll hazard a guess:Public Function Build64(ByVal value As Object) As UInt64 Dim ui64High As UInt64 = value.high Dim ui64Low As UInt64 = (value.low And 0x00000000FFFFFFFF) ui64High = ui64High << 32 Return Convert.ToUInt64(ui64High Or ui64Low) End Function
You shouldn't need to mask the high value since you'll be shifting it left anyway.
EDIT: Adding an explanation as to why ABS wouldn't work
When you're generating the binary for the 64 bit number, the low 32 bits need to be exactly the same as the 32 bits used in the low value you're given. Doing an absolute value calculation will change those bits very significantly.
For a really simple example, say the low value is -5.
-5 in binary (just one byte to make it easier) is: 11111011
Abs(-5) = 5, which in binary is: 00000101
In 2s complement numbers, Abs(val) is equivalent to (~val) + 1, where ~ is the binary complement operator, which changes all 0s to 1s and all 1s to 0s.
Thus, using the ABS of the low value will give you almost the exact opposite of the binary data you should have in the low 32 bits of the final number. - Andy_Herrman_22
Nimbostratus
Looking back at your previous posts, you probably need to do use Convert.ToUInt64() in a couple places there for it to work. - Mike_Thompson_9
Nimbostratus
For the life of me I cannot get this figured out. It all has to do with that negative number coming back for the value.low and converting it to a UInt64. Any other CommonULong64 which does not contain a negative number works fine.
Can anyone else please shed some light on this? Really need to get this figured out and it really should not be this difficult! - I've been working on this as well and have been having the same issues as you have. Any time a conversion from your -176378626 to a unsigned integer is causing an overflow. -176378626 should equate to 4118588670 as a unsigned 32 bit value but it seems however I try, I can't get VB to do that conversion. C handle it fine with it's dynamic casting, but for some reason VB keeps overflowing.
I'll keep pounding, but for the life of me I can't get VB do do the conversion. For reference, This is what should be the true valueshigh = 4, low = -176378626 (4118588670)
val = (high << 32) | low
high << 32 -> 0x0000000400000000
low -> 0x00000000F57CACFE
value64 -> 0x00000004F57CACFE
value64 -> 18446744073533172990
Just as an aside, you cannot convert -1 into a unsigned number it seems:Dim ui64 As UInt32 = Convert.ToUInt32(-1)
The value should be 4294967295 but it results in an overflow exception.
If anyone out there understands the insides of VB's type system enough to make sense out of this, if you would please chime in, we'd really appreciate it.
Any chance on writing the method that does the conversion in C?
-Joe - Mike_Thompson_9
Nimbostratus
Yeah, that was my thought exactly. Write just the piece that does the conversion in C, then worry about figuring the solution in VB later. At least this would get me going. However, I am certain this can be done in VB, just have to muddle through it to get the solution.
I started discussing the problem with some of the guys around the office and came up with a few ideas which I have not had a chance to try, but plan to do so first thin in the morning. Thanks for those values, that will help. When or if I get the solution in VB, I will be sure to post ASAP.
As Joe said, if anyone has any insight on how to resolve the problem in the interim, please chime in....
Mike - Andy_Herrman_22
Nimbostratus
Another option would be to split the low value into two positive ints (basically, getting a lowLow and lowHigh value).
Here's what I mean (in pseudocode and extra verbose as I don't know VB and want to be clear):int32 high = value.high; int32 low = value.low; int32 lowLow = value.low & 0x0000FFFF; int32 lowHigh = (value.low >> 16) & 0x0000FFFF; uint64 high64 = Convert.ToUInt64(high); uint64 lowLow64 = Convert.ToUInt64(lowLow); uint64 lowHigh64 = Convert.ToUInt64(lowHigh); uint64 final = (high64 << 32) | (lowHigh64 << 16) | lowLow64; return final;
By splitting the low value into two 16-bit values stored in 32-bit ints neither will be negative. This should fix the problem with Convert.ToUInt64.
If you're worried about the high value getting so large that it becomes negative then you might want to do the same to the high value, but that's up to you.
Hope that helps (and that it works)!
Recent Discussions
Related Content
DevCentral Quicklinks
* Getting Started on DevCentral
* Community Guidelines
* Community Terms of Use / EULA
* Community Ranking Explained
* Community Resources
* Contact the DevCentral Team
* Update MFA on account.f5.com
Discover DevCentral Connects
