如何从二进制文件中读取单精度浮点数并转换为Erlang浮点数?

时间:2016-09-21 07:07:00

标签: floating-point erlang

我使用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.

2 个答案:

答案 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。您可以将其明确指定为biglittlenative