# Conversion Problem

OK, maybe it’s because it’s late and I’m about ready to poke my eyes out but I’m having a problem with a conversion from binary to double…

I’m taking an IP address and converting it to binary form. The code I have to do this is all correct. I have verified that I am getting the proper binary numbers represented as strings in Xojo. Now I want to covert them to their decimal value. So I am doing this:

Dim MyNumber as Double = CDbl("&b"+MyBinaryString)

I’m getting a number like: -1408237567

Which doesn’t make much sense. It can’t be that I’m hitting the limit of Double as that is a very large number…

What am I doing wrong?

Thanks!

Wouldn’t it be easier to take each octet from the IP address and stuff them byte-by-byte into a memoryblock, then pull the UInt32 out of that? How is it that you’ve got binary representation in the first place?

``````dim ip as string = "192.169.0.10"
dim octets() as string = split(s, ".")
dim mb as new memoryblock(4)
for i = 0 to 3
mb.byte(i) = val(octets(i))
next
dim address as UInt32 = mb.UInt32Value(0)``````

Most probably the decimal number -1408237567 is decimal representation of the binary value of IPv4 address 172.16.0.1. Here the decimal 172 converted to binary is 1010 1100. With most significant bit=1, this should be a negative number of type Double.

``` // // 172.16.0.1 = 1010 1100 0001 0000 0000 0000 0000 0001 //```

[quote=143507:@Jon Ogden]OK, maybe it’s because it’s late and I’m about ready to poke my eyes out but I’m having a problem with a conversion from binary to double…

I’m taking an IP address and converting it to binary form. The code I have to do this is all correct. I have verified that I am getting the proper binary numbers represented as strings in Xojo. Now I want to covert them to their decimal value. So I am doing this:

Dim MyNumber as Double = CDbl("&b"+MyBinaryString)

I’m getting a number like: -1408237567

Which doesn’t make much sense. It can’t be that I’m hitting the limit of Double as that is a very large number…

What am I doing wrong?

Thanks![/quote]
Why a double ?
An integer (32 or 64 bit) would be a lot simpler to it mask or just dump it in a MemoryBlock & grab the Unit8’s from that to get your octets

Now when we start getting IP V6 addresses … ick !

Both CDbl and Val seem to switch to interpreting the Hex/Binary input as “2’s Complement” representation of the number if the input Hex/Binary has four hex octets or more (32 or more bits). In this case, if the most significant bit is 1 then the number is interpreted as negative.

``````Dim dblNum As Double

//
// Result = 255
//
// 2's Complement interpretation is not applied, even though the most significant bit=1
//
dblNum = CDbl( "&b11111111")

//
// Result = 65535
//
// 2's Complement interpretation is not applied, even though the most significant bit=1
//
dblNum = CDbl( "&b1111111111111111")

//
// Result = 16777215 ( 1.677722e+7)
//
// 2's Complement interpretation is not applied, even though the most significant bit=1
//
dblNum = CDbl( "&b111111111111111111111111")

//
// Result /= 4294967295, instead Result = -1
//
// 2's Complement interpretation is applied, most significant bit=1
// So invert all bits and add 1 and also place the negative sign
//
//    11111111111111111111111111111111
//  - 00000000000000000000000000000000
//  +                                1
// ------------------------------------
//  - 00000000000000000000000000000001 This is -1
//
dblNum = CDbl( "&b11111111111111111111111111111111")

//
// IPv4 Address 172.10.0.1 converted to binary as 1010 1100  0001 0000  0000 0000  0000 0001
//
// Result /= 2886729729, instead Result = -1408237567 (-1.408238e+9)
//
// 2's Complement interpretation is applied, most significant bit=1
// So invert all bits and add 1 and also place the negative sign
//
//    10101100000100000000000000000001
//  - 01010011111011111111111111111110
//  +                                1
// ------------------------------------
//  - 01010011111011111111111111111111 This is - 1408237567
//
dblNum = CDbl( "&b10101100000100000000000000000001") ``````

Based on above details, one could guess that somehow an Int32 (signed 32 bit Integer) is being used while converting numbers/strings (with CDbl and Val functions) that are less than 64 bit in size. That could explain why the one, two and three octet negative numbers (in 2’s Complement representation) do not get converted to a nagative decimal number because the most significant bit (bit-31in Int32 data type, zero based counting) remains 0 for these numbers. However this only remains a guess at this time.

[quote=143518:@Tim Hare]Wouldn’t it be easier to take each octet from the IP address and stuff them byte-by-byte into a memoryblock, then pull the UInt32 out of that? How is it that you’ve got binary representation in the first place?

``` dim ip as string = "192.169.0.10" dim octets() as string = split(s, ".") dim mb as new memoryblock(4) for i = 0 to 3 mb.byte(i) = val(octets(i)) next dim address as UInt32 = mb.UInt32Value(0) ```[/quote]

The problem isn’t getting a binary from the IP address. I’m doing it a bit differently than you. I break it into Octets and then I convert each octet to a binary string using the Bin function. Then in order to make it into an 8 bit binary number, I pad zeros were needed. So for example:

If you convert 1 to binary you get just 1. But I need it to be: 00000001.
If you convert 16 to binary, you get: 10000. But it needs to be 00010000.

So then once I do that for each octet, I concatenate the strings back together to get the full 32 bit number. It works great. I’ve confirmed it’s correct comparing IP addresses conversions in my code versus a website I found that does it.

The conversion back to a base ten number is what is giving me problems. I don’t see how it’s giving me a negative number…

[quote=143532:@Norman Palardy]Why a double ?
An integer (32 or 64 bit) would be a lot simpler to it mask or just dump it in a MemoryBlock & grab the Unit8’s from that to get your octets

Now when we start getting IP V6 addresses … ick ![/quote]

Why a double - because I was experimenting. I tried Int32 and got the incorrect conversion. So that’s why…

I’ve not thought about putting it into the memory block. Let me go try that…

[quote=143518:@Tim Hare]Wouldn’t it be easier to take each octet from the IP address and stuff them byte-by-byte into a memoryblock, then pull the UInt32 out of that? How is it that you’ve got binary representation in the first place?

``` dim ip as string = "192.169.0.10" dim octets() as string = split(s, ".") dim mb as new memoryblock(4) for i = 0 to 3 mb.byte(i) = val(octets(i)) next dim address as UInt32 = mb.UInt32Value(0) ```[/quote]

OK, Tim and Norman, I don’t think you guys quite understand what I am trying to do.

If I put an IP address into a memory block like Tim suggests above and then pull that out as suggested, all I am doing is converting the values of the octets from Strings to Integers. In that case, it would be simpler to do this:

``````Dim ip as String  = "192.168.1.10"
Dim octets as string = ip.split(".")

Dim Intvals(4) as UInt8

For i as integer = 0 to 3
Intvals(i) = val(Octets(i))
Next``````

No need for a memory block. But that is NOT what I want.

I want to get the actual base 10 numerical value for the IP address. An IP address that we know and love is a set of 4 octets with each octet representing an 8 bit binary word. The entire IP address is a 32 bit binary word. That 32 bit binary word has a base 10 representation. I want that.

The reason is I am writing code to determine if an IP address is in a given subnet. So for my subnet, I know my starting IP and I know my ending IP. Then to determine if the IP in question is in the network, I simply need to convert their 32 bit binary values to base 10 and compare them since I can’t do binary math in Xojo.

But CDBL is not giving me the correct answer.

[quote=143530:@Syed Hassan]Most probably the decimal number -1408237567 is decimal representation of the binary value of IPv4 address 172.16.0.1. Here the decimal 172 converted to binary is 1010 1100. With most significant bit=1, this should be a negative number of type Double.

``` // // 172.16.0.1 = 1010 1100 0001 0000 0000 0000 0000 0001 //```[/quote]

No, this isn’t correct.

172.16.0.1 in Binary is: 10101100000100000000000000000001
10101100000100000000000000000001 converted to Decimal is: 5773459458

But CDbl gives a completely wrong number -1408237567.

That is my issue. Everyone is focused on how I am handling the iP. I’m generating the 32 bit binary word just fine. It’s converting it to Decimal that appears to go awry in Xojo.

When I paste 5773459458 into the OS X Calculator and check programmer view it shows a 33 bit number. There’s an extra 0.

101011000001000000000000000000010

Typing in these bits

10101100000100000000000000000001

It shows this decimal value 2886729729

I got “172.16.0.1” -> 2886729729 using Tims code and adding LittleEndian False

```Sub Action() dim ip as string = "172.16.0.1" //"192.169.0.10" dim octets() as string = split(ip, ".") dim mb as new memoryblock(4) mb.LittleEndian = False for i As integer = 0 to 3 mb.byte(i) = val(octets(i)) next dim address as UInt32 = mb.UInt32Value(0) TextArea1.Text = Str(address) End Sub```

[quote=143582:@Will Shank]When I paste 5773459458 into the OS X Calculator and check programmer view it shows a 33 bit number. There’s an extra 0.

101011000001000000000000000000010

Typing in these bits

10101100000100000000000000000001

It shows this decimal value 2886729729[/quote]

Yeah, I just saw that. I copied and pasted wrong! Oop!

[quote=143586:@Will Shank]I got “172.16.0.1” -> 2886729729 using Tims code and adding LittleEndian False

```Sub Action() dim ip as string = "172.16.0.1" //"192.169.0.10" dim octets() as string = split(ip, ".") dim mb as new memoryblock(4) mb.LittleEndian = False for i As integer = 0 to 3 mb.byte(i) = val(octets(i)) next dim address as UInt32 = mb.UInt32Value(0) TextArea1.Text = Str(address) End Sub```[/quote]

Oh. I see what I did wrong then. Tim’s code didn’t make sense on first look - why was he only pulling from the first element of the memory block. So I confused it with norms. Now, I get it - you put in 8 bit numbers into each segment of the memory block, then you pull out the 32 bit number. Now that makes sense.

Oh, that is much easier than what I did. Still, I’ve had a fun learning experience and now I’ve just written a method that will convert from any base to decimal.

[quote=143576:@Jon Ogden]I don’t think you guys quite understand what I am trying to do.

But CDBL is not giving me the correct answer.[/quote]
The reported problem is very well understood.

The cause of CDbl giving negative result for the indicated IPv4 Address 172.16.0.1 is already provided in previous post in the last example.

The following code gives correct Decimal value result of 2886729729.

[code]Dim intU32Num As UInt32

intU32Num = CDbl( “&b10101100000100000000000000000001”)
MsgBox( Str( intU32Num))

intU32Num = Val( “&b10101100000100000000000000000001”)
MsgBox( Str( intU32Num))
[/code]

huh? So there wasn’t a problem to begin with?

Oh I see. The result of CDbl or Val has to be explicitly typed as Unsigned otherwise it’s interpreted signed

[code] dim s As String = “&b10101100000100000000000000000001”

MsgBox Str(Val(s)) //-1.408238e+9

MsgBox Str( CType(Val(s), UInt32) ) //2886729729

dim ui As UInt32 = Val(s)
MsgBox Str(ui) //2886729729

dim i As Int32 = Val(s)
MsgBox Str(i) //-1408237567

dim d As double = Val(s)
MsgBox Str(d) //-1.408238e+9[/code]

Not mine - i’ve not pasted any code
Just asked why you were using a double
I’d be using a Uint32

[quote=143594:@Norman Palardy]Not mine - i’ve not pasted any code
Just asked why you were using a double
I’d be using a Uint32[/quote]

No, you didn’t, but you said:

So I started grabbing the Unit8s and just saw that gave me my octets back as numbers. That’s where I got confused…

I’m not very well schooled in using memory blocks, but the way it works with Tim’s and William’s code works really well. William is correct - you do need to set LittleEndian to false.

Now, that I understand how to use a memory block to make a conversion like this, that is really cool. Gotta keep learning. Thanks for the help guys!

Maybe we should do a session on “Bit Twiddling in Xojo” at XDC.

Bitwise operations on 32-bit integers is very common and easy to do in Xojo. AND, OR and XOR are now built-in binary operators. Other operations require using the BITWISE object.

In particular, IP4 addresses were designed for bitwise manipulation. Answering the question, “Is this address in my subnet?” is a single line of code.

``if IPAdresss AND SubnetMask = SubnetMask then  // it's in the subnet``

[quote=143610:@Tim Hare]Maybe we should do a session on “Bit Twiddling in Xojo” at XDC.

Bitwise operations on 32-bit integers is very common and easy to do in Xojo. AND, OR and XOR are now built-in binary operators. Other operations require using the BITWISE object.

In particular, IP4 addresses were designed for bitwise manipulation. Answering the question, “Is this address in my subnet?” is a single line of code.

``` if IPAdresss AND SubnetMask = SubnetMask then // it's in the subnet ```[/quote]

Wow. Seriously that easy? Holy Smokes.

But that can certainly tell you if a particular address is valid for a particular subnet. But let’s say I have an IP address of 192.168.1.10 with a 24 bit subnet mask. My bonjour method discovers a new device I want to connect that has an IP address of 192.168.200.5. I don’t see how doing an AND between 192.168.200.5 and 255.255.255.0 is going to mean anything valid. 192.168.200.5 is certainly a valid address for a 24 bit subnet mask. But 192.168.200.5 is NOT in the 24 bit 192.168.1.0 network that 192.168.1.10 is part of.

So help me understand this better because really, nearly any IP4 address is going to be a valid address in just about any subnet mask.

In the example of IP Address 192.168.1.10 and Subnet Mask of 255.255.255.0, the related Network Address is the bitwise AND of the IP Address and the Subnet Mask, resulting in Network Address of 192.168.1.0. Any other IP Address will also be part of this network if the bitwise AND of that IP Address and the Subnet Mask 255.255.255.0 results in the same Network Address 192.168.1.0.

IP Address 192.168.200.5 does not seem to be part of the same network because bitwise AND of 192.169.200.5 and 255.255.255.0 results in Network Address of 192.169.200.0.

So the correct check of same network could be…

``` // // Determine if IPAddress1 and IPAddress2 are on the same network having Subnet Mask = SubnetMask // If IPAddress1 AND SubnetMask = IPAddress2 AND SubnetMask Then // End If```