代码在这里:
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
}
浮点数精度改变了! 我怎么能解决这个问题?
答案 0 :(得分:2)
让我们看一下rfc4627
生成的JSON:
> io:format("~s~n", [rfc4627:encode({obj, [{"age", 45.99}]})]).
{"age":4.59900000000000019895e+01}
事实证明rfc4627
通过调用float_to_list/1
来编码浮点值,As Per Hedeland noted on the erlang-questions mailing list in November 2007使用20位精度的“科学”符号。 Is floating point math broken?,这是一个奇怪的选择:
一个合理的问题可能是float_to_list / 1生成20位数的原因 当一个64位浮点数(a.k.a。C double),这是内部使用的, 只能容纳15-16的价值 - 我不知道128位的副手 浮动会有,但可能会超过20,所以事实并非如此 那个。我想回到黑暗时代,有人认为20 是一个很好的偶数(我希望不是我:-)。 6.30000表格是 当然只是~p / ~w格式化。
然而,事实证明这实际上不是问题!实际上,45.990000000000002
等于45.99
,因此您做在前端获得正确的值:
> 45.990000000000002 =:= 45.99.
true
如上所述,64位浮点数可以包含15或16位有效数字,但45.990000000000002
包含17位数(计算它们!)。看起来您的前端尝试以比实际包含的更精确的方式打印数字,从而使得看起来的数量不同,即使它实际上是相同的数字。
问题{{3}}的答案更详细地说明了为什么这实际上有意义,考虑到计算机如何处理浮点值。
答案 1 :(得分:0)
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).
解决了问题。