我使用Erlang在二进制文件中读取了4个字节(小端)。
在尝试将二进制转换为浮点数时,我一直遇到以下错误:
** exception error: bad argument
in function list_to_integer/1
called as list_to_integer([188,159,21,66])
它似乎不匹配浮动模式,而是最终调用list_to_integer。如何将我的单精度浮点数转换为原生的Erlang浮点数?
我的Erlang功能如下:
readfloat(S, StartPos) ->
io:format("Pos: ~w~n", [StartPos - 1]),
case file:pread(S, StartPos - 1, 4) of
eof ->
ok;
{ok, Data} ->
% io:format("Wut: ~w~n", Data),
N = binary_to_list(Data),
case string:to_float(N) of
{error,no_float} ->
list_to_integer(N);
{F,_Rest} ->
F
end
% have tried this section as well, error too
% N = binary_to_list(Data),
% try list_to_float(N)
% catch
% error:badarg ->
% list_to_integer(N)
% end
end.
答案 0 :(得分:6)
如果您知道刚刚读取的4个字节是单精度浮点数的二进制表示(根据IEEE 754),您可以使用Wikipedia page给出的定义将其转换为浮点数:
1> Float = fun(B) -> <<S:1,E:8,M:23>> = B,
1> case {S,E,M} of
1> {_,0,0} -> 0; % you may make distinction between +0 and -0
1> {1,255,0} -> minus_infinity;
1> {0,255,0} -> infinity;
1> {_,255,_} -> nan;
1> {S,0,M} -> (1-2*S)*M/(1 bsl 149); % denormalized number
1> {S,E,M} when E > 150 -> float((1-2*S)*(M+ (1 bsl 23)) * (1 bsl (E - 150)));
1> {S,E,M} -> (1-2*S)*(M+ (1 bsl 23))/(1 bsl (150-E))
1> end
1> end. 1>end. #Fun<erl_eval.6.52032458>
2> Float(<<192,0,0,0>>).
-2.0
3> Float(<<188,159,21,66>>).
-0.019419316202402115
4> Float(<<194,237,64,0>>).
-118.625
[编辑] 像往常一样我太迟了:o),我不记得二进制匹配的语法:<<Z:32/float>>
:o(
答案 1 :(得分:5)
string:to_float
期望参数是数字的打印表示,但在这种情况下,您有二进制表示。您可以使用bit syntax expression转换它。
> Y = <<188,159,21,66>>.
<<188,159,21,66>>
> <<Z:32/float-little>> = Y.
<<188,159,21,66>>
> Z.
37.40599060058594
即,对二进制执行模式匹配,并提取一个小端32位浮点数,并将其赋值给变量Z
。
注意:如果您没有指定字节序,则Erlang默认为big endian。您可以将其明确指定为big
,little
或native
。