【问题标题】:Erlang cowboy reply json data , float number precision is wrong?Erlang牛仔回复json数据,浮点数精度不对?
【发布时间】:2017-07-09 04:18:53
【问题描述】:

代码在这里:

RstJson = rfc4627:encode({obj, [{"age", 45.99}]}),
{ok, Req3} = cowboy_req:reply(200, [{<<"Content-Type">>, <<"application/json;charset=UTF-8">>}], RstJson, Req2)

然后我从前端客户端得到这个错误的数据:

{
  "age": 45.990000000000002
}

浮点数精度改变了! 我该如何解决这个问题?

【问题讨论】:

  • 您能否将代码发布到接收该数据的客户端上?我会冒险它与 JavaScript 有关。

标签: json erlang cowboy rfc4627


【解决方案1】:

rfc4627中的编码浮点数函数是:

encode_number(Num, Acc) when is_float(Num) ->
  lists:reverse(float_to_list(Num), Acc).

我是这样改的:

encode_number(Num, Acc) when is_float(Num) ->
  lists:reverse(io_lib:format("~p",[Num]), Acc).

问题解决了。

【讨论】:

    【解决方案2】:

    我们来看看rfc4627生成的JSON:

    > io:format("~s~n", [rfc4627:encode({obj, [{"age", 45.99}]})]).
    {"age":4.59900000000000019895e+01}
    

    原来rfc4627 通过调用float_to_list/1 对浮点值进行编码,float_to_list/1 使用精度为 20 位的“科学”表示法。 As Per Hedeland noted on the erlang-questions mailing list in November 2007,这是一个奇怪的选择:

    一个合理的问题可能是为什么 float_to_list/1 会生成 20 位数字 当内部使用的 64 位浮点数(又名 C 双精度)时, 只能容纳 15-16 个 - 我不知道 128 位是什么 float 会有,但可能远远超过 20,所以它不是 那要么。我想回到黑暗时代,有人认为 20 是一个很好的偶数(我希望不是我:-)。 6.30000 形式是 当然只是 ~p/~w 格式。


    然而,事实证明这实际上不是问题!事实上,45.990000000000002 等于 45.99,所以你确实在前端得到了正确的值:

    > 45.990000000000002 =:= 45.99.
    true
    

    如上所述,64 位浮点数可以容纳 15 或 16 位有效数字,但 45.990000000000002 包含 17 位数字(数一数!)。看起来您的前端试图以比实际包含的精度更高的精度打印数字,从而使数字看起来不同,即使它实际上是相同的数字。


    鉴于计算机如何处理浮点值,Is floating point math broken? 问题的答案更详细地说明了为什么这实际上是有意义的。

    【讨论】:

      猜你喜欢
      • 2019-05-09
      • 2020-09-05
      • 2020-02-03
      • 1970-01-01
      • 2021-05-09
      • 1970-01-01
      • 2018-02-23
      • 1970-01-01
      • 2017-02-19
      相关资源
      最近更新 更多