2017-02-20 3 views
1

code est ici:Erlang cowboy réponse données json, la précision du nombre de flotteur est faux?

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

puis-je obtenir ce mal les données du client avant:

{ 
    "age": 45.990000000000002 
} 

le nombre flottant de précision est changé! comment puis-je résoudre ce problème?

+1

Pourriez-vous publier le code sur le client qui reçoit ces données? Je l'aventure c'est quelque chose à voir avec JavaScript. –

Répondre

3

Jetons un coup d'oeil au JSON rfc4627 génère:

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

Il se trouve que rfc4627 encode les valeurs à virgule flottante en appelant float_to_list/1, qui utilise la notation « scientifique » avec 20 chiffres de précision. As Per Hedeland noted on the erlang-questions mailing list in November 2007, c'est un choix étrange:

Une question raisonnable pourrait être la raison pour laquelle float_to_list/1 génère 20 chiffres quand un flotteur 64 bits (alias C double), qui est ce qui est utilisé en interne, ne peut contenir 15 Je ne sais pas ce qu'un flotteur de 128 bits aurait, mais vraisemblablement beaucoup plus de 20, donc ce n'est pas non plus. Je suppose que dans les âges sombres, quelqu'un pensait que 20 était un nombre gentil et pair (j'espère que ce n'était pas moi :-). Le formulaire 6.30000 est bien sûr juste le formatage ~ p/~ w.


Cependant, il se trouve c'est en fait pas le problème! En fait, 45.990000000000002 est égal à 45.99, de sorte que vous faire obtenir la valeur correcte à l'avant:

> 45.990000000000002 =:= 45.99. 
true 

Comme il est indiqué ci-dessus, un flotteur 64 bits peut contenir 15 ou 16 chiffres significatifs, mais 45.990000000000002 contient 17 chiffres (comptez-les!). Il semble que votre frontal essaie d'imprimer le numéro avec plus de précision qu'il n'en contient réellement, ce qui rend le numéro différent même s'il s'agit en fait du même numéro.


Les réponses à la question Is floating point math broken? vont beaucoup plus de détails sur les raisons de ce fait réellement sens, étant donné la façon dont les ordinateurs gèrent des valeurs à virgule flottante.

0

la fonction du numéro de flotteur encode en rfc4627 est:

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

je l'ai changé comme ceci:

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

Problème résolu.