Ruby 等效于 C# BitConverter.ToSingle

Ruby equivalent for C# BitConverter.ToSingle

我们从客户的 API 接收到一个十六进制字符串,我们应该从中提取不同的值。

在用于转换提取数据的算法中,使用了方法 BitConverter.ToSingle(four_bytes, 0)

经过大量试验和错误后,我发现 Ruby 中的这条神奇的代码行得通,但不要问我为什么...

def convert(four_bytes)
  four_bytes.map { |i| [i.to_s(16)].pack('H2') }.join.unpack('e').first
end

它似乎适用于几乎所有情况,但客户只是报告了一些它不适用的情况。

因为我不太明白这里发生了什么,所以我真的很困惑,不知道要寻找什么。

这是一个案例,与大多数案例一样,结果是相同的:

convert([35, 55, 90, 67])       => 218.21538 # Ruby
BitConverter.ToSingle(bytes, 0) => 218.21538 # C#

这是我们遇到的不同之处:

                                    v
convert([119, 175, 2, 67])      => 160.68541 # Ruby
BitConverter.ToSingle(bytes, 0) => 130.68541 # C#
                                    ^

Ruby 方法有什么问题? 你会怎么做?

对发生的事情的一些解释加分!

Ruby String#to_i 使用所需的最少位数,而 .pack 命令恰好需要两个才能将每个 nybble 正确放置在构造的浮点数中。

所以当任何字节为0-15时,转换就会出错。

要解决此问题,请始终转换为 two-digit 十六进制字符串。 sprintf 可以做到这一点,所以以下将起作用:

def convert(four_bytes)
  four_bytes.map { |i| [sprintf('%02x',i)].pack('H2') }.join.unpack('e').first
end