2016-02-29 8 views
12

Niektóre interfejsy API, takie jak paypal API, używają typu łańcucha w JSON do reprezentowania liczby dziesiętnej. Tak więc "7.47" zamiast 7.47.Dlaczego należy użyć ciągu znaków w JSON do reprezentowania liczby dziesiętnej

Dlaczego/kiedy byłby to dobry pomysł na używanie typu wartości json? AFAIK typ wartości liczbowej pozwala na nieskończoną precyzję oraz notację naukową.

+2

ponieważ używanie kursorów dla waluty spowoduje tylko błędy na drodze. pływaki NIE nadają się do reprezentowania rzeczywistych wartości, takich jak pieniądze - i to niezawodnie. na przykład 7.47 może faktycznie być 7.4699999923423423423 po konwersji na zmienną. prosty system, który po prostu obcina dodatkowe cyfry, spowoduje 7.46, a teraz straciłeś grosz w jakimś ... odcieniu Supermana II (I?). –

+2

@MarcB Jestem zaznajomiony z tym, dlaczego nie użyłbyś float dla waluty, ale czy numer JSON jest rzeczywiście zmiennoprzecinkowy? Jak rozumiem, jest to numer niezależny od języka i można sparsować numer JSON bezpośrednio do formatu 'BigDecmial' lub innego dowolnego formatu precyzji w dowolnym języku, jeśli jest tak skłonny. – kag0

+0

zależy od tego, od czego to było w systemie Paypal. json to odwzorowanie 1: 1 między monolitycznym ciągiem tekstowym a strukturą danych JS. jeśli "liczba" jest zapisana jako ciąg "" ... "' w łańcuchu json, to był ciąg znaków w pierwotnej strukturze danych lub coś, co odwzorowuje łańcuch. –

Odpowiedz

14

Głównym powodem przesyłania wartości liczbowych w JSON jako łańcuchy jest wyeliminowanie utraty dokładności lub niejednoznaczności w przenoszeniu.

To prawda, że ​​specyfikacja JSON nie określa dokładności wartości numerycznych. Nie oznacza to, że numery JSON mają nieskończoną precyzję. Oznacza to, że precyzja numeryczna nie jest określona, ​​co oznacza, że ​​implementacje JSON mogą dowolnie wybierać dowolną precyzję liczbową dogodną dla ich implementacji lub celów. To właśnie ta zmienność może być uciążliwa, jeśli twoja aplikacja ma określone wymagania precyzji.

Utrata precyzji na ogół nie jest widoczna w kodowaniu JSON wartości numerycznej (1.7 jest ładne i zwięzłe), lecz manifestuje się w analizie JSON i reprezentacjach pośrednich na końcu odbierającym. Funkcja parsowania JSON całkiem sparsuje 1,7 na liczbę zmiennoprzecinkową podwójnej precyzji IEEE. Jednak reprezentacje o skończonej długości/skończonej precyzji zawsze będą trafiały na liczby, które nie mogą być dokładnie odwzorowane. Numery irracjonalne (jak pi i e) nigdy nie mogą być dokładnie przedstawione w skończonym systemie. 1.7 ma skończoną reprezentację w zapisie dziesiętnym (podstawa 10), ale w postaci binarnej (podstawa 2) jest liczbą niewymierną - nieskończoną serią cyfr.

Zatem, parsowanie 1.7 do liczby zmiennoprzecinkowej w pamięci, wydrukowanie numeru prawdopodobnie zwróci wartość 1,69 - nie 1,7.

Konsumenci wartości JSON 1.7 mogą używać bardziej wyrafinowanych technik do analizowania i zatrzymywania wartości w pamięci, na przykład z użyciem typu danych o stałych punktach lub typu danych "ciąg int" z dowolną precyzją, ale nie będzie to całkowicie wyeliminować widmo utraty precyzji w konwersji dla niektórych liczb. Rzeczywistość jest taka, że ​​bardzo niewiele parserów JSON zajmuje się tak ekstremalnymi środkami, ponieważ korzyści dla większości sytuacji są niskie, a koszty pamięci i procesora są wysokie.

Więc jeśli chcesz wysłać dokładną wartość liczbową do konsumenta i nie chcesz automatycznej konwersji wartości do typowej wewnętrznej reprezentacji numerycznej, najlepiej jest wysłać wartość liczbową jako ciąg znaków i dokładnie poinformuj konsumenta, jak ten ciąg powinien zostać przetworzony, jeśli i kiedy należy wykonać na nim operacje numeryczne.

Na przykład: W przypadku niektórych producentów JSON (JRuby, dla jednego), wartości BigInteger automatycznie wyprowadzane są na JSON jako łańcuchy, w dużej mierze dlatego, że zakres i precyzja BigIntegera jest znacznie większa niż zmienna podwójna precyzja IEEE. Zmniejszenie wartości BigInteger do podwójnej wartości wyjściowej jako liczby JSON często powoduje utratę znaczących cyfr.

Ponadto specyfikacja JSON (http://www.json.org/) wyraźnie stwierdza, że ​​NaNs i Infinities (INF) są nieprawidłowe dla wartości numerycznych JSON. Jeśli chcesz wyrazić te elementy, nie możesz użyć numeru JSON. Musisz użyć ciągu lub struktury obiektu.

Wreszcie istnieje inny aspekt, który może prowadzić do wyboru wysyłania danych numerycznych jako ciągi: kontrola formatowania wyświetlania. Zerujące się zera i końcowe zera są nieistotne dla wartości liczbowej. Jeśli wyślesz wartość numeru JSON 2.10 lub 004, po konwersji do wewnętrznej formy numerycznej będą wyświetlane jako 2.1 i 4.

Jeśli wysyłasz dane, które będą bezpośrednio wyświetlane użytkownikowi, prawdopodobnie chcesz, aby Twoje dane pieniężne były ładnie wyrównane na ekranie z wyrównaniem dziesiętnym. Jednym ze sposobów jest uczynienie klienta odpowiedzialnym za formatowanie danych do wyświetlenia. Innym sposobem na to jest, aby serwer formatował dane do wyświetlenia. Prostsze dla klienta, aby wyświetlać treść na ekranie, ale może to spowodować, że wyodrębnienie wartości liczbowej z ciągu będzie trudne, jeśli klient będzie musiał wykonać obliczenia na wartościach.

+0

Nie lekceważ znaczenia liczb nieracjonalnych - jest o wiele więcej liczb nieracjonalnych niż liczb wymiernych! Oba są nieskończonymi zbiorami, ale miara irracjonalności jest większa niż miara rozumowania. Zapytaj swoją lokalną matematykę prof. Przynieś kawę. :> – dthorpe

+1

Czy możesz podać kilka przykładów klientów, którzy tracą precyzję kodowania? Na przykład, Jackson w Javie z łatwością przekształci dziesiętny json w BigDecimal bez utraty precyzji. To frustrujące, że czyjeś API jest mniej dokładne (nie jest to ciąg znaków, jest to liczba, która jest czymś, co obsługuje json) tylko dlatego, że niektórzy nienazwani klienci robią to, co uważam za "niewłaściwe", gdy otrzymam numer json. –

0

skrócona wersja

Wystarczy przytoczyć od użytkownika @ dthorpe odpowiedź, jak myślę, że jest to najważniejszy punkt:

Również spec JSON (http://www.json.org/) wyraźnie stwierdza, że ​​Koncepcja nieliczby i Nieskończoność (plików INF) są nieprawidłowe dla wartości numerycznych JSON. Jeśli chcesz wyrazić te elementy, nie możesz użyć numeru JSON. Musisz użyć ciągu lub struktury obiektu.

Powiązane problemy