Кодирование/декодирование JSON и потеря точности во float'ах

334 views
Skip to first unread message

Alexander Alexeev

unread,
Feb 10, 2014, 2:01:56 AM2/10/14
to erlang-...@googlegroups.com
Всем привет.

Не сталкивался ли кто с такой проблемой и если да, то как ее решали?

Допустим, мы работаем с decimal'ами. Пользователи ходят к нам через
REST. Простейший способ отдать им JSON с чиселками - сказать
decimal_conv:float и jsx:encode. Аналогично с декодированием.

Но тут есть проблема, что число типа 0.17 может прийти в JSON'е как
0.17000000001. Очевидное решение - передавать числа в виде строк, но
это почему-то не очень нравится нашим коллегам-скалистам.

Есть ли простой и не костыльный способ правильно закодировать decimal с
помощью decimal_conv:string и вставить результат вот прямо в JSON,
чтобы получилась все-таки число?

--
Best regards,
Alexander Alexeev
http://eax.me/

Mikhail Gusarov

unread,
Feb 10, 2014, 2:47:52 AM2/10/14
to erlang-...@googlegroups.com
Ходить через float, естественно, не надо, это теряет точность.
Впрочем, и в jsx не видно опции для того, чтобы отформатировать данные
специальным способом.


Best regards,
Mikhail Gusarov.
> --
> Вы получили это сообщение, поскольку подписаны на группу Erlang по-русски.
>
> Чтобы отказаться от подписки на эту группу и перестать получать из нее сообщения, отправьте электронное письмо на адрес erlang-russia...@googlegroups.com.
> Чтобы добавлять сообщения в эту группу, отправьте письмо по адресу erlang-...@googlegroups.com.
> Настройки подписки и доставки писем: https://groups.google.com/groups/opt_out.

Илья Аржанников

unread,
Feb 10, 2014, 3:09:46 AM2/10/14
to erlang-...@googlegroups.com
Так-то json потдерживает только или int или float. Но обычно, что бы засунуть в json какуе-нибудь структуру делают по прицепу питонячего __repr__, то есть, что бы из строки было понятно, во что это превратить.
Например {«data»: «DateTime(2013, 1, 1, 0, 0, 0)», «const»: «Decimal(10, 10)»}
Это решит проблему с точностью и позволит парсеру не привязываться к именам полей

Dmitrii Dimandt

unread,
Feb 10, 2014, 3:46:24 AM2/10/14
to erlang-...@googlegroups.com
«data»: «DateTime(2013, 1, 1, 0, 0, 0)» — это уже RPC, а не REST

Для таких вещей, как datetime давным давно существует ISO 8601, не выдумывайте велосипедов :)
Практически единственная проблема — да, это float’ы. И то, надо смотреть, что именно за данные передаются, и нельзя ли их передать либо в виде integer’ов либо в виде пары {value: integer(), unit: any()}

ну и http://tools.ietf.org/html/rfc4627.html#section-2.4





On 10 Feb 2014 09:09:46 , Илья Аржанников <iarzha...@gmail.com> wrote:

Илья Аржанников

unread,
Feb 10, 2014, 3:55:18 AM2/10/14
to erlang-...@googlegroups.com
ISO 8601 никак не противоречит тому что я написал. В скобках DateTime() можно писать хоть ISO хоть еще чего, лишь бы на той стороне знали, что с этим делать. Такая костыльная типизация для типов которые легко представимы ввиде строк, но строками не являются. Если не нравиться «DateTime()» можно еще об чем-нибуль договорится. 

Mikhail Gusarov

unread,
Feb 10, 2014, 4:25:11 AM2/10/14
to erlang-...@googlegroups.com
JSON поддерживает десятичные дробные числа произвольной длины и
точности (ECMA-404 8).

Т.е. проблема с представлением 0.17 - это ограничение библиотеки,
которая принимает только IEEE floating point-число, а не произвольную
десятичную дробь.


Best regards,
Mikhail Gusarov.

Dmitrii Dimandt

unread,
Feb 10, 2014, 4:35:25 AM2/10/14
to erlang-...@googlegroups.com
2014-02-10 9:55 GMT+01:00 Илья Аржанников <iarzha...@gmail.com>:
ISO 8601 никак не противоречит тому что я написал. В скобках DateTime() можно писать хоть ISO хоть еще чего, лишь бы на той стороне знали, что с этим делать.


Ээээ, вообще-то противоречит. ISO 8601 на то и ISO, чтобы вокруг него ничего не надо было дополнительного писать :) Если другая сторона не знает, что в поле "date" должна быть дата, то у вас проблемы с определением протокола обмена данными :)

 
Такая костыльная типизация для типов которые легко представимы ввиде строк, но строками не являются. Если не нравиться «DateTime()» можно еще об чем-нибуль договорится. 

Договариваются ровно об одном: поле "date" объекта содержит дату в формате ISO 8601 — и все. Какие "DateTime(...)", о чем вы? :)


create_time: Time of refund as defined in RFC 3339 Section 5.6 

Все. Если другая сторона не знает, что create_time — это время в этом формате, то это проблема другой стороны :) Не надо наворачивать костыли поверх врапперов поверх RPC :) Надо сесть, понять, что вы передаете, и соответственно разработать протокол.
Reply all
Reply to author
Forward
0 new messages