Visual Basic 2010:最近在我的一个项目中,我的任务是以十六进制读取几个数据字段。每个字段长三个字符。所以这就是我一直在做的事情:
'Read the hex value and convert it to decimal
Dim hexVal as string = "38D"
Dim intVal as integer = Convert.ToInt32(hexVal, 16)
'The integer result gets multiplied by a scaling factor
'(this is set by the manufacturer for each field).
Dim fac as single = 200
Dim final as single = intVal * fac
Debug.Print (final)
除了在这种情况下,这一直很有效:hexVal =“FFD”和fac = 32 .NET给我intVal = 4093,最终= 130976。 然而,我正在检查的遗留系统给出了-96。
我有点困惑,但理论上它是十六进制表示法。我对原始数据的唯一文档说明:字符按ISO字母5号编码,每个字符使用7位,即没有添加奇偶校验位。三个这样的字符将包含每个32位字的字段。
我是否错误地转换了这个?
附录:我已经研究了这些领域的定义,并发现几乎所有领域都是积极的(或未签名的)。少数可以是消极的或积极的(签名的)。查看遗留代码,对于每个十六进制字段,它们计算无符号结果和签名结果。如果预期该字段始终为正,则它们使用无符号结果。现在,如果该字段预期为负数或正数,则它们采用无符号结果,如果高于上限,则使用签名结果,否则使用无符号结果。以下是我到目前为止使用下面的片段:
Dim hexVal As String, res As Single, decCeiling As Single
Dim paddedHex1 As String, intVal1 As Integer = 0, resVal1 As Single = 0
Dim paddedHex2 As String, intVal2 As Integer = 0, resVal2 As Single = 0
Dim IsUnsignedInput As Boolean
hexVal = "FB1" 'Raw hex input (in this case represents temperature in deg C)
res = 0.125 'A resolution factor. Used to scale the decimal to a real-world nummber
decCeiling = 150 'The maximum temperature we can expect is 150 degree Celcius
IsUnsignedInput = False 'Is field unsigned or signed (for temps we can expect negative and positive)
If hexVal.Length > 8 Then
Throw New Exception("Input '" & hexVal & "' exceeds the max length of a raw input. The max is 8 characters.")
EndIf
'This calcualtion assumes an unsigned value (that is, always a positive number)
paddedHex1 = hexVal.ToString.PadLeft(8, CChar("0"))
intVal1 = Convert.ToInt32(paddedHex1, 16)
resVal1 = intVal1 * res
'This assumes a signed value (that is, could be a negative OR positive number.
'Use two's complement to arrive at the result.
paddedHex2 = hexVal.PadLeft(8, CChar("F"))
Dim sb As New StringBuilder(paddedHex2.Length)
For i As Integer = 0 To paddedHex2.Length - 1
Dim hexDigit As Integer = Convert.ToInt32(paddedHex2(i), 16)
sb.Append((15 - hexDigit).ToString("X"))
Next i
Dim inverted As Integer = Convert.ToInt32(sb.ToString, 16)
intVal2 = -(inverted + 1)
resVal2 = intVal2 * res
'Finally, which result do we use as the final decimal? For our example we get
'resVal1 (unsigned)=+502.125
'resVal2 (signed) = -9.875
'Field is signed so is 502.125 > 150? Yes, so use the signed result of -9.875.
If IsUnsignedInput Then
'If unsigned then we always expect a positive value so use straight conversion.
Debug.Print("Result=" & resVal1)
Else
'If signed then we expect a positive OR negative value
If resVal1 > decCeiling Then
'Standard conversion yields a higher number than expected so use two's complement to get number
Debug.Print("Result=" & resVal2)
Else
'Standard conversion yields a number that is in the expected range so use straight conversion to get number
Debug.Print("Result=" & resVal1)
End If
End If
与遗留系统进行背靠背比较,它们都匹配,但过去不能使用hex,我有点谨慎。对于这种方法的任何进一步反馈,我将不胜感激。
答案 0 :(得分:4)
intVal = 4093是正确的 final = 130976也是正确的。
FFD
也可以解释为-3表示在双补码中(计算机如何存储负值)。 32 * -3 = -96。
FFD = 111111111101 (binary)
在二进制补码中,当第一位为1
时,表示该数字为负数。为了否定数字,首先反转所有位然后加1:
FFD inverted = 000000000010
+ 1 = 000000000011 = 3 (decimal).
由于3是否定数,因此实数必须为-3。
您也可以使用Hex表示法执行此操作。如果第一个十六进制数字是> = 8,则您有一个负数。因此,通过执行以下替换来否定数字:
0 -> F
1 -> E
2 -> D
3 -> C
4 -> B
5 -> A
6 -> 9
7 -> 8
8 -> 7
9 -> 6
A -> 5
B -> 4
C -> 3
D -> 2
E -> 1
F -> 0
(第二列只是以相反的顺序列出十六进制数字。)
因此对于FFD,你得到002(十六进制)。您可以将此十六进制数转换为十进制数并添加1,然后得到3.因为这表示负值,请将其乘以-1。 3 * -1 = -3。
Function ConvertHex(ByVal hexVal As String) As Integer
If hexVal(0) >= "8"c Then 'We have a negative value in the 2's complement
Dim sb As New System.Text.StringBuilder(hexVal.Length)
For i As Integer = 0 To hexVal.Length - 1
'Convert one hex digit into an Integer
Dim hexDigit As Integer = Convert.ToInt32(hexVal(i), 16)
'Invert and append it as hex digit
sb.Append((15 - hexDigit).ToString("X"))
Next i
'Get the inverted hex number as Integer again
Dim inverted As Integer = Convert.ToInt32(sb.ToString(), 16)
'Add 1 to the inverted number in order to get the 2's complement
Return -(inverted + 1)
Else
Return Convert.ToInt32(hexVal, 16)
End If
End Function
但是如果你总是有3个十六进制数字,你可以简单地执行此操作
Function ConvertHex3(ByVal hexVal As String) As Integer
Dim number = Convert.ToInt32(hexVal, 16)
If hexVal(0) >= "8"c Then
Return number - &H1000
Else
Return number
End If
End Function
那更聪明!