Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IEEE quad floats in typed arrays, but not as single values #226

Open
ecorm opened this issue Feb 27, 2021 · 2 comments
Open

IEEE quad floats in typed arrays, but not as single values #226

ecorm opened this issue Feb 27, 2021 · 2 comments

Comments

@ecorm
Copy link

ecorm commented Feb 27, 2021

The current standard does not allow 128-bit IEEE quad floats as single values (major type 7, minor type 28), whereas they are allowed in typed arrays (tag 87). This leads to the vexing situation where an application can efficiently transfer arrays of IEEE quad floats, but not single values without resorting to the Bigfloat tag (5). This feels inconsistent and lacks "symmetry".

Is there a reason to not assign major 7, minor type 28 now as 128-bit IEEE float? Why wait?

If the argument is that 128-bit IEEE floats are not natively supported on many platforms, then why are there 16-bit half floats?

@cabo
Copy link
Collaborator

cabo commented Feb 27, 2021

When CBOR was defined in 2013, we focused on constrained nodes, where 128-bit floats seemed preposterous (while 16-bit was quite pertinent).
So we left additional information 28 to 30 for future standardization. When the specification was promoted to Internet Standard, we didn't have use cases that were asking for doing that extension.
Of course, when we did the work for RFC 8746, we noticed that it was a bit weird to have arrays for 128-bit floats, but no single values. On the other hand, including binary128 seemed appropriate in the matrix that RFC8746 is based on.

So you can send an array, not a single value. (Of course you can send the single value using Tag 5, but that requires some bit fiddling.) But then, it is not that much worse to prefix a 16-byte binary128 with 0xD85370 than with 0xFC, so we felt this gave us an easy way to accommodate binary128 at least in some form.

Since 2003, I have heard occasional talk about use cases both for binary128 and for 128-bit integers. So maybe time is ripe for this extension. Maybe you can describe your use case in a little more detail? I can imagine there will be quite some pushback, because this would be the first technical change to CBOR outside its well-defined extension points.
So the argument will need to be well-made.

If this doesn't fly, we can always define a few more tags that operate on 16-byte byte strings (we'd need float, uint, and nint, I think). Two bytes more, which is 12 % above the 17 bytes needed for the ai=28 solution.

@ecorm
Copy link
Author

ecorm commented Feb 27, 2021

My use case is a bit complicated, but here goes. I'm writing (yet another) general-purpose C++ serialization library that can be extended for any JSON-like codec (JSON, CBOR, YAML, Msgpack, etc). My CBOR encoder can be configured to disable typed arrays for situations where it is known that the receiver does not understand typed array tags. When typed arrays are disabled, array-like data structures will always be encoded as regular arrays.

My library has a "transcode" feature where it decodes any JSON-like entity, and produces the equivalent encoded output in either the same or a different encoding.

So here's my vexing situation. Let's say the transcoding is set-up with a CBOR input decoder with typed arrays enabled, and a CBOR output encoder with typed arrays disabled. In this situation, whenever the transcoder detects an input typed array, it will emit a regular non-typed array of discrete numeric values. All possible typed array types have an equivalent discrete CBOR value type, except for binary128. This is what I mean by "lack of symmetry".

I don't personally have a need for 128-bit floats in my applications, but I do want my serialization library to be as general-purpose as possible. My options here are:

  1. Abandon support for binary128 typed arrays altogether since I can't easily transcode to discrete binary128 values.
  2. Transcode binary128 values as either BigFloat or HalfFloat (the latter in case of infinity/NaN).
  3. Invent a tag for quad-precision IEEE floats, to be encoded as a 16-byte byte string (as you suggested).

With the BigFloat workaround, the receiver has to do a bunch of bit fiddling and math to determine if the BigFloat can be safely interpreted as an IEEE binary128. This is because the BigFloat exponent would need to be at least 3 bytes to account for the IEEE implicit exponent offset. The receiver would also need to check if it received a HalfFloat in the case of infinity or NaN. You see how messy this is.

With new multi-precision IEEE float tags, there will end up being redundant ways of encoding big IEEE floats if it is later decided to "unreserve" minor types 28 to 30. This may not even be a problem -- I'm not sure really. New multi-precision IEEE float tags seem to be the best interim solution for me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants