【问题标题】:How to read single precision float from binary file and convert to Erlang float?如何从二进制文件中读取单精度浮点数并转换为 Erlang 浮点数?
【发布时间】:2016-09-21 18:59:39
【问题描述】:

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

【问题讨论】:

    标签: floating-point erlang


    【解决方案1】:

    如果您知道刚刚读取的 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
    

    [Edit] 像往常一样,我来不及了 :o),我不记得二进制匹配的语法:&lt;&lt;Z:32/float&gt;&gt; :o(

    【讨论】:

    • 完美解决方案!很少能看到详细的二进制数学。谢谢。
    【解决方案2】:

    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
    

    即对二进制执行模式匹配,提取一个little-endian 32位浮点数,并将其分配给变量Z

    注意:如果你不指定字节序,Erlang 默认为大字节序。您可以将其明确指定为biglittlenative

    【讨论】:

      猜你喜欢
      • 2020-02-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-17
      • 2014-02-07
      • 1970-01-01
      • 2011-05-09
      • 1970-01-01
      相关资源
      最近更新 更多