简体   繁体   English

Erlang Cowboy回复json数据,浮点数精度错误?

[英]Erlang cowboy reply json data , float number precision is wrong?

code is here : 代码在这里:

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

then I get this wrong data from front client: 然后我从前端客户那里得到了错误的数据:

{
  "age": 45.990000000000002
}

the float number precision is changed ! 浮点数精度已更改! how can I solved this problem? 我该如何解决这个问题?

Let's have a look at the JSON that rfc4627 generates: 让我们看一下rfc4627生成的JSON:

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

It turns out that rfc4627 encodes floating-point values by calling float_to_list/1 , which uses "scientific" notation with 20 digits of precision. 事实证明, rfc4627通过调用float_to_list/1 rfc4627编码浮点值,该方法使用精度为20位的“科学”表示法。 As Per Hedeland noted on the erlang-questions mailing list in November 2007 , that's an odd choice: 正如Per Hedeland在2007年11月的erlang-questions邮件列表中指出的那样 ,这是一个奇怪的选择:

A reasonable question could be why float_to_list/1 generates 20 digits when a 64-bit float (aka C double), which is what is used internally, only can hold 15-16 worth of them - I don't know off-hand what a 128-bit float would have, but presumably significantly more than 20, so it's not that either. 一个合理的问题可能是为什么当内部使用的64位浮点数(又名C双精度数)只能容纳15-16个浮点数时,为什么float_to_list / 1生成20位数字-我不知道该用什么一个128位浮点数将具有,但大概超过20个,因此也不是。 I guess way back in the dark ages, someone thought that 20 was a nice and even number (I hope it wasn't me:-). 我想可以追溯到黑暗时代,有人认为20是个不错的甚至是个数字(我希望不是我:-)。 The 6.30000 form is of course just the ~p/~w formatting. 6.30000格式当然只是〜p /〜w格式。


However, it turns out this is actually not the problem! 但是,事实证明这实际上不是问题! In fact, 45.990000000000002 is equal to 45.99 , so you do get the correct value in the front end: 实际上, 45.990000000000002等于45.99 ,因此您在前端确实获得了正确的值:

> 45.990000000000002 =:= 45.99.
true

As noted above, a 64-bit float can hold 15 or 16 significant digits, but 45.990000000000002 contains 17 digits (count them!). 如上所述,一个64位浮点数可以容纳15或16个有效数字,但是45.990000000000002包含17个数字(计数!)。 It looks like your front end tries to print the number with more precision than it actually contains, thereby making the number look different even though it is in fact the same number. 看起来您的前端试图打印比实际包含的精度更高的数字,从而使数字看起来不同,即使实际上是相同的数字也是如此。


The answers to the question Is floating point math broken? 问题的答案浮点数学运算是否已损坏? go into much more detail about why this actually makes sense, given how computers handle floating point values. 考虑到计算机如何处理浮点值,我们将详细介绍为什么这实际上有意义。

the encode float number function in rfc4627 is : rfc4627中的编码浮点数函数为:

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

I changed it like this : 我这样改变了它:

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

Problem Solved. 问题解决了。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM