如何在Erlang中读取2字节浮点



在其他语言中似乎有很多半浮点问题,但找不到Erlang的问题。

所以,我有一个2字节的浮点,作为一个较长的二进制模式输入的一部分。我尝试使用像<<AFloat:16/float>>这样的模式匹配,但在编译器中得到了警告/错误,而使用32/float则没有产生警告。

问题是:Erlang中有什么变通方法可以将2字节二进制转换为浮点?

我看到了"从Erlang中的二进制文件读取"的另一个详细的位处理答案,不知道在这种情况下是否需要它。

*感谢您提供以下答案。我稍后会试用*

--两组样本输入:EF401C3FEA3F、1242C341C341

Erlang似乎不支持32和64以外的浮点宽度(至少目前是这样(,但我似乎找不到任何明确说明这一点的文档。

更新:我检查了位语法的实现,它肯定只处理32和64位浮点。这确实应该有更好的记录。

再次更新:现已添加到上游文档中。

最后更新:刚刚看到你关于十六进制输入的注释。如果你第一步解决了这个问题,将十六进制字符串H转换为具有实际数据字节的二进制B,你可以使用以下方法将数据重新打包为32位浮点(一个简单的转换(,然后以正常方式提取这些数据:

Floats = [F || <<F:32/float>> <- [<<S:1,(E+(127-15)):8,(M bsl 13):23>> || <<S:1,E:5,M:10>> <- B]]

不支持16位浮点。如果你想收集并处理来自另一个系统的float(例如通过文件(,那么你可以很容易地将这个float转换为你的VM中使用的表示。

首先读取文件并将float16提取为2字节二进制文件,然后调用此转换函数:

-module (float16).
-export([conv_16_to_vm/1]).
% conv_16_to_vm(binary) with binary is a 16 bit float representation
conv_16_to_vm(<<S:1,E:5,M:10>>)->
conv(S,E,M).
conv(_,0,0) -> 0.0;
conv(_,31,_) -> {error,nan_or_qnan_or_infinity};
% Sign management
conv(1,E,M) -> -conv(0,E,M);
% sub normal floats
conv(0,0,M) -> M/(1 bsl 24);
% normal floats
conv(0,E,M) when E < 25 -> (1024 + M)/(1 bsl (25-E));
conv(0,25,M) -> (1024 + M);
conv(0,E,M) -> (1024 + M)*(1 bsl (E-25)).

我使用了维基百科提供的定义,你可以测试一下:

1> c(float16).                      
{ok,float16}
2> float16:conv_16_to_vm(<<0,1>>).      % 0 00000 0000000001
5.960464477539063e-8
3> float16:conv_16_to_vm(<<3,255>>).    % 0 00011 1111111111
6.097555160522461e-5
4> float16:conv_16_to_vm(<<4,0>>).      % 0 00100 0000000000
6.103515625e-5
5> float16:conv_16_to_vm(<<123,255>>).  % 0 11110 1111111111
65504
6> float16:conv_16_to_vm(<<60,0>>).     % 0 01111 0000000000
1.0
7> float16:conv_16_to_vm(<<60,1>>).     % 0 01111 0000000001
1.0009765625
8> float16:conv_16_to_vm(<<59,255>>).   % 0 01110 1111111111
0.99951171875
8> float16:conv_16_to_vm(<<53,85>>).    % 0 01101 0101010101
0.333251953125

正如您所料,传统的问题或"舍入"更加明显。

最新更新