2014-09-10 4 views
2

Visual Basic 2010 : 최근에 내 프로젝트 중 하나에서 16 진수로 여러 데이터 필드를 읽는 작업을했습니다. 각 필드는 3 자입니다. hexVal = "FFD을"및 FAC = 32 .NET 나에게 INTVAL = 4093을 제공하고 최종 = 130,976이이 경우를 제외하고 좋은 일하고있다16 진수 문자열을 정수로 변환

'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) 

: 그래서 내가하고 있었던 것입니다. 그러나 내가 검사하는 레거시 시스템은 -96을 제공합니다.

저는 조금 혼란 스럽지만 16 진수 표기법이라고 이론합니다. 원시 데이터에 대한 유일한 문서는 다음과 같습니다. 문자는 ISO 알파벳 번호 5에 따라 문자 당 7 비트, 즉 패리티 비트를 추가하지 않고 코드화됩니다. 3 개의 문자가 각 32 비트 단어의 필드로 구성됩니다.

잘못 변환합니까?

부록 : 필드의 정의를 살펴본 결과 거의 모든 것이 양수 (또는 서명되지 않음)가 될 것으로 예상됩니다. 몇 가지는 음수 또는 양수일 수 있습니다 (서명 됨). 레거시 코드를 살펴보면 각 16 진수 필드에 대해 부호없는 결과와 부호가있는 결과가 계산됩니다. 필드가 항상 양수가 될 것으로 예상되면 부호없는 결과를 사용합니다. 이제 필드가 음수 또는 양수인 것으로 예상되면 부호없는 결과를 취하고, 한도가 높은 경우 부호있는 결과를 사용하고 그렇지 않으면 부호없는 결과를 사용합니다. 여기에 지금까지 아래에서 조각과 함께하는 것입니다 : 모두가 일치하는 기존의 시스템과 백 - 투 - 백 비교를하는

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 

하지만 과거에 너무 많은 진수 작동하지 않습니다, 나는 조금 신중하다. 이 접근법에 대한 추가 의견을 보내 주시면 감사하겠습니다.

답변

4

intVal = 4093이 정확합니다.
final = 130976도 올바른 것입니다.

FFD 또한 2의 보수로 표시되는 -3으로 해석 될 수 있습니다 (컴퓨터가 음수 값을 저장하는 방식입니다). 32 * -3 = -96. 첫 번째 비트가 1 경우 2의 보수에서

FFD    = 111111111101 (binary) 

는, 상기 번호가 음을 의미한다. 먼저, 부정 횟수를 모든 비트를 반전하고 1을 위해 추가 3 이후

FFD inverted =  000000000010 
+ 1   =  000000000011 = 3 (decimal). 

가 부정 번호, 실수 -3이어야한다.

16 진수 표기법으로도이 작업을 수행 할 수 있습니다. 처음 16 진수가 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 

(두 번째 열은 단순히 역순으로 16 진수를 보여줍니다.)

그래서 FFD 당신은 002 (16 진수)를 얻는다. 이 16 진수를 십진수로 변환하고 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 16 진수가있는 경우 당신은 단순히 훨씬 똑똑 즉,이

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 

할 수 있습니다!

+0

그래서 내 목표가 레거시 시스템에서 수행하는 .NET 응용 프로그램을 만드는 것이라면 여기에 어떤 경로를 제안 하시겠습니까? 다른 유형의 전환 방법으로 전환해야합니까? – sinDizzy

+0

감사! 솔직히 두 번째 편집에서 나는 최종 일과의 절반 정도를 가지고있었습니다. Dim C는 Char = { "8"c, "9"c, "A"c, "B"c, "C"c, "D"로 char = CChar (hexVal.Substring (0) "c", E "c", "F"c} 그런 다음 Dim IsNeg As Boolean = highBits.Contains (c). 하지만 네가 훨씬 더 간결하다. – sinDizzy

+0

ok 레거시 시스템 프로그래머로부터 약간의 정보를 얻고 있습니다. 그는 일반적으로 음수 값을 가질 수있는 필드는 길이가 4 또는 8 자의 16 진수 문자가 될 것이라고 말합니다. 명령 줄 변환에서 레거시 시스템을 사용하는 경우 TOHEX -3 = FFFFFFFD이고 TOHEX 2068 = 00000814입니다. TODEC FFD = 4093 및 TODEC 814 = 2068과 같은 내부 루틴에서 8자를 예상합니다. In 위의 루틴은 0x814 = -2028입니다. 나는 레거시 시스템이 어떤 조정을하고 있는지 알지 못한다. 8자를 조정합니까? 4 또는 8 문자를 얻기 위해 16 진수 값을 패드에 두어야합니까? – sinDizzy