Visual Basic 2010: 最近、私のプロジェクトの 1 つで、いくつかのデータ フィールドを 16 進数で読み取る作業を担当しました。各フィールドの長さは 3 文字です。だからこれは私がやっていることです:
'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 と final=130976 を与えます。しかし、私がチェックしている従来のシステムでは -96 が返されます。
私は少し混乱していますが、16 進数表記であると理論付けています。生データについて私が持っている唯一の文書には、次のように記載されています。文字は、1 文字あたり 7 ビットを使用して、つまりパリティ ビットを追加せずに、ISO アルファベット No 5 に従ってコード化されています。このような 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
従来のシステムと背中合わせに比較すると、すべて一致しますが、過去に 16 進数であまり機能していないので、少し注意が必要です。このアプローチに関するさらなるフィードバックをいただければ幸いです。