【问题标题】:Convert floating point byte array to decimal将浮点字节数组转换为十进制
【发布时间】:2018-07-26 09:22:17
【问题描述】:

我通过 BLE 收到一个 4 字节长的数组,我有兴趣将 最后两个字节 转换为 浮点 十进制表示(float, @987654322 @ 等)在 C# 中。原始值具有以下格式:

 1 sign bit 
 4 integer bits 
11 fractional bits

我的第一次尝试是使用BitConverter,但我对这个过程感到困惑。

示例:我收到一个byte 数组values,其中values[2] = 143values[3] = 231。这 2 个字节组合起来代表上面指定格式的值。我不确定,但我认为应该是这样的:

SIGN  INT FRACTION  
   0 0000 00000000000

此外,由于该值包含两个字节,我尝试使用BitConverter.ToString 来获取十六进制表示,然后连接字节。在这一点上,我不确定如何继续。

感谢您的帮助!

【问题讨论】:

  • 举个例子...信息太少...小数位如何表示?在 12.345 中,345 是小数位吗? (和 12 个整数位)
  • 如果出现“values[2] = 143values[3] = 231”,答案是什么?是-1.987793吗?
  • 是的,对于那些值,我使用您的实现得到 -1.987793
  • @John Szatmari:请问“values[2] = 143values[3] = 231”的正确答案是什么?如果你真的有,比如说,一些奇怪的 BCD,你可能想要一些其他的实现。

标签: c# floating-point bluetooth-lowenergy


【解决方案1】:

您的问题缺少信息,但格式似乎很清楚,例如对于给定的两个字节作为

  byte[] arr = new byte[] { 123, 45 };

我们有

 01111011 00101101
 ^^  ^^    ..    ^
 ||  ||          |  
 ||  |11 fractional bits = 01100101101 (813)
 ||..|  
 |4 integer bits         =        1111 (15)
 | 
 1 sign bit              =           0 (positive)

让我们得到所有的部分:

 bool isNegative =  (arr[0] & 0b10000000) != 0;
 int intPart     =  (arr[0] & 0b01111000) >> 3;
 int fracPart    = ((arr[0] & 0b00000111) << 8) | arr[1];

现在我们应该将所有这些部分组合成一个数字;这是歧义:计算小数部分有许多可能的不同方法。其中之一是

 result = [sign] * (intPart + fracPart / 2**Number_Of_Frac_Bits) 

在我们的例子中 { 123, 45 } 我们有

 sign     = 0 (positive)
 intPart  = 1111b = 15 
 fracPart = 01100101101b / (2**11) = 813 / 2048 = 0.39697265625

 result   = 15.39697265625

实施:

 // double result = (isNegative ? -1 : 1) * (intPart + fracPart / 2048.0);
 Single result = (isNegative ? -1 : 1) * (intPart + fracPart / 2048f);

 Console.Write(result);

结果:

 15.39697

编辑: 如果您实际上 没有 符号位,但使用 2 的补码 作为整数部分(即 不寻常 - doublefloat 使用 sign bit;2 的补码用于 integer 类型,例如 Int32Int16 等)我 期待 em> 只是一个期望,2 的补码在上下文中是不寻常的)类似于

  int intPart  =  (arr[0]) >> 3;
  int fracPart = ((arr[0] & 0b00000111) << 8) | arr[1];

  if (intPart >= 16) 
    intPart = -((intPart ^ 0b11111) + 1);

  Single result = (intPart + fracPart / 2048f);

另一种可能,您实际上使用 整数 值 (Int16) 和 固定浮点;在这种情况下,转换很容易:

  1. 我们照常获取Int16
  2. 然后把固定浮点数除以2048.0:

代码:

  // -14.01221 for { 143, 231 }
  Single result = unchecked((Int16) ((arr[0] << 8) | arr[1])) / 2048f;

或者

  Single result = BitConverter.ToInt16(BitConverter.IsLittleEndian 
    ? arr.Reverse().ToArray() 
    : arr, 0) / 2048f;

【讨论】:

  • 感谢您的详尽回复!我刚刚发现原始值应该是 2 的补码,在这种情况下,我想乘以符号不会这样做。将值转换为 16 位 Int,取补并加 1 工作吗?
  • @John Szatmari:不,在您的情况下,要获得 2 的补码,整数部分是 int intPart = (arr[0]) &gt;&gt; 3; 然后是 if (intPart &gt;= 16) intPart = -((intPart ^ 0b11111) + 1);。请注意,您只需要 16Int16包含16时>5位补码
  • @Dimitry Bychenko:你说得对,我实际上是在使用 整数 (Int16) 值和固定浮点。再次感谢您的帮助!
  • @John Szatmari:不客气!下次请不要忘记提供例子让我们不要猜测(如果你有符号位或2的补码,或固定浮点数)
猜你喜欢
  • 2014-03-01
  • 1970-01-01
  • 2013-05-22
  • 2014-11-24
  • 2010-12-08
  • 2016-06-02
  • 1970-01-01
  • 2016-12-16
相关资源
最近更新 更多