kdl-org / kdl

the kdl document language specifications
https://kdl.dev
Other
1.1k stars 61 forks source link

Non-decimal floats? #216

Closed clarfonthey closed 9 months ago

clarfonthey commented 2 years ago

The official spec doesn't allow for binary, octal, or hexadecimal floats, although there isn't a particular reason why it couldn't. They work exactly the same as decimal floats, just with the prefix at the beginning. For example, 0x1.8 is 0x18 / 0x10 or 1.5.

Note that there is precedent from C++ to include hexadecimal floats, although I don't know of any language that also offers octal and binary floats as well.

My main motivation for this is because I have some data from ICC profiles which I want to represent exactly as given, but with decimal floats there will always be some sort of rounding error. For example, a profile might store a number as 0x0000.9c18, which wouldn't convert precisely into a decimal float.

The biggest change is that instead of e representing an exponent for these floats, the character C++ uses is p to indicate a power of the radix, which I would say makes the most sense. Link to that spec here: https://en.cppreference.com/w/cpp/language/floating_literal

clarfonthey commented 2 years ago

I also am not used to GitHub discussions existing, so if this would make more sense over there I can move this.

djmattyg007 commented 2 years ago

I think it would be better to introduce a fractional type, where both the numerator and denominator can be represented in either binary, octal, hexadecimal or decimal. This would let you cleanly represent any real number that cannot be accurately represented as a floating point number with limited precision.

hkolbeck commented 2 years ago

I think a fraction format would be very cool, but I'm hesitant to prescribe too much implementation detail, and requiring the ability to exactly encode arbitrary fractions feels like step in that direction.

zkat commented 2 years ago

My main rationale for not having a Rational/fraction format is exactly that: It adds a lot of implementation complexity for something that is, honestly, probably going to be a niche feature in practice. I'd rather not do that, considering how few languages have built-in support for these.

clarfonthey commented 2 years ago

The main reason why I mention non-decimal floats is that they are similar enough to existing floats that implementing them shouldn't be too much of a burden, and they already have accepted syntax as well. Whereas fractions ask a whole load of questions that are hard to answer:

Meanwhile the most complicated question for non-decimal floats is how exponents should work, and what character(s) should be used in place of e. And that already is mostly solved as C++ uses p for hex floats and it'd be a horrible mistake IMHO to change that.

There is the question of whether p should also be used by octal and binary floats, but even then, there could also be the option to just allow hex floats like C++. Lot of options there.

tabatkins commented 2 years ago

Implementing non-decimal floats actually would be a burden for most implementations, I'd think. A "parseInt()" or similar function that can take an arbitrary (2-36) base is pretty common, but parseFloat() rarely has an allowed base. (Neither JS nor Python offer this as built-in, for example.) So while binary/octal/hex can today be implemented by just collecting the characters and passing them to a built-in function to get the numeric value, doing the same with non-decimal floats would require writing our own string-to-number functions. (Which aren't remotely hard, but still.)

That said, supporting arbitrary value formats is pretty much exactly what value tags were designed for: (hex)"0.9c18", for example. You get perfect passthru of the value, and then can interpret it into the desired value at the end.

zkat commented 9 months ago

I'm just gonna reject this one as out-of-scope. It's super niche and almost certainly a massive implementation burden.