2017-02-20 4 views
1

コードはここにある:Erlangカウボーイ返信jsonデータ、浮動小数点数の精度が間違っていますか?

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 
} 

フロート数の精度が変更されました! この問題を解決するにはどうすればよいですか?

+1

そのデータを受け取るクライアントにコードを投稿できますか?私はそれがJavaScriptと関係があると冒険するだろう。 –

答えて

3

のはrfc4627が生成するJSONを見てみましょう:

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

をそれはrfc4627は精度の20桁の「科学的」表記を使用する、float_to_list/1を呼び出すことにより、浮動小数点値をコードしていることが判明しました。

float_to_list/1が内部的に使用されているものである20桁 時に64ビット浮動小数点(別名C二重)を生成する理由を合理的な質問は可能性があり、 はわずか15を保持することができます:As Per Hedeland noted on the erlang-questions mailing list in November 2007、それは奇妙な選択です-16の価値があります。私は128ビットの 浮動小数点数には何があるのか​​分かりませんが、おそらく20を超えるので、それは ではありません。私は暗黒時代に戻って、誰かが20 が素敵で偶数であると思った(私はそれが私ではないことを願っています:-)。 6.30000形式は、 です。もちろん、〜p /〜w形式だけです。


しかし、これは実際には問題ではありませんが判明!上述したように

> 45.990000000000002 =:= 45.99. 
true 

、64ビット浮動小数点は15または16桁を保持することができますが、45.990000000000002が含まれています。実際には、45.990000000000002はあなたがは、フロントエンドに正しい値を得るのですかので、45.99に等しく、 17桁(数えて!)。フロントエンドが実際に含まれているよりも高い精度で番号を印刷しようとしているため、実際には同じ番号であってもの外観はと異なっています。


質問Is floating point math broken?への回答は、これが実際にコンピュータが浮動小数点値をどのように処理するかを考えると、理にかなっている理由についてはあまり詳細に入ります。

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). 

問題は解決します。

関連する問題