在其他语言中似乎有很多半浮点问题,但找不到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
正如您所料,传统的问题或"舍入"更加明显。