JSON+LD
JSON-LD 1.1 defines A JSON-based Serialization for Linked Data that became a W3C Recommendation on 16 July 2020.
JSON+LD proposes to re-specify some features to make it usable for communication in financial services.
Decimal Numbers
JSON+LD distinguishes decimal and binary numbers.
JSON natively represents decimal numbers with an arbitrary length, sclae and precision. It does not natively represent infinities, not a numbers, recurring numbers, nor subnormal numbers. This means they are a strict subset of xsd:precisionDecimal, which is intended to align with IEEE type decimal128. Java’s BigDecimal is another suitable representation.
We recommend defining JSON:number as per its lexical definition, and the value space represented by that. This then allows applications to determine correspondance and translation.
For example:
As all JSON:number are also in xsd:precisionDecimal, they map cleanly without conversion. However, the xsd:precisionDecimal “positive infinity” doesn’t have a corresponding value in JSON:number; instead it could be mapped to the JSON-LD object {“@type”:”xsd:precisionDecimal”, “@value”:”+INF”}
The JSON-LD 1.1 specification defines:
a number (numbers with a non-zero fractional part, i.e., the result of a modulo‑1 operation, or which are too large to represent as integers (see Data Round Tripping) in [JSON-LD11-API]), are interpreted as typed values with type
https://www.w3.org/TR/json-ld/#data-modelxsd:double
, all other numbers are interpreted as typed values with typexsd:integer
),
and acknowledges this differs from a common RDF format with a note:
Note that this interpretation differs from [Turtle], in which the literal
https://www.w3.org/TR/json-ld/#conversion-of-native-data-types2.78
translates to anxsd:decimal
. The rationale is that most JSON tools parse numbers with fractions as floating point numbers, soxsd:double
is the most appropriate datatype to render them back in RDF.
The problem with this assumption is that even simple decimal fractions are rounded in their binary floating point representation.
For example, the number one-tenth is in the value space neither of float nor of double; the string ‘
https://www.w3.org/TR/xsd-precisionDecimal/#pD-lexical-mapping0.1
‘ maps, in double, to 0.100000000000000055511151231257827021181583404541015625.
[and for float] to the value 0.100000001490116119384765625.
So 10% of a billion dollars becomes $100,000,001.49. This means there is now a reconciliation issues to sort out where the chump change came from.
A fairly high impact if your doing thousands of transactions each year.
It’s better to use decimal arithmetic with decimal rounding of decimal values in decimal notation.
Round trip conversion
How can we have a general approach to get the best round trip conversion?
In RDF 1.1, it is implicit that literals have a datatype. It is explicit that its datatype may have many IRIs. In “normal” RDF triple, literals can only be the object. In Generalized RDF Triples, literals can also be the subject or predicate of a triple, which permits a literal to have several datatypes JSON-LD supports generalized RDF triples, and explicitly permits multiple values.
So it is possible to state that {“@value”:123 , “@type”:[“xsd:integer”, “xsd:decimal”, “xsd:precisionDecimal”, “xsd:double”]
There are relationships between the datatypes.
- xsd:integer rdfs:subClassOf xsd:decimal .
- xsd:decimal rdfs:subClassOf xsd:precisionDecimal .
but not
- xsd:integer rdfs:subClassOf xsd:double
as there are integers outside the range of double,
However, we want conversion that is friendly to the native format.
A JSON number 123 can be converted to a TTL literal as 123 with an implied type of xsd:integer, which can be converted back to the JSON number 123.
0.5 is a decimal, and a double.
0.1 is a decimal, but is not a double.
0.5E1 is a double, and a precisionDecimal, but is not a decimal.
We recommended that to enable friendly native round trip conversion, that the native representation compatible with the type is used.
Types which are explicitly specified should be indicated as such, and carried over where this is the user preference.
Internal representation of decimal
The IEEE Standard for Floating-Point Arithmetic (IEEE 754) 2008,
specifies representation of decimal numbers.
Name | Base | Significand | Exponent |
binary64 (double precision) | 2 | 53 bits (~16 digits) | 11 bits (~±308) |
decimal32 | 10 | 7 digits | ±96 |
decimal64 | 10 | 16 digits | ±384 |
decimal128 | 10 | 34 digits | ±6144 |