Discussion of op:same-key

Andy -

Could you please add an agenda item to discuss op:same-key?

First off, I'll declare that implementing op:same-key for numeric values 
is something of a pain on .NET.  The specification requires numeric 
values to be considered equal if the values are mathematically equal.  
The specification guides the implementer to conversion of xs:float, 
xs:decimal and xs:decimal to a representation of a decimal number 
without rounding or loss of precision, thus achieving a transitive 
comparison.

.NET provides no arbitrary precision decimal type, and this makes 
implementation something of a burden.

Test cases have shown that the requirement throws up some undesirable 
implementation incompatibilities e.g. test "same-key-008"

             map {
               1 div 3 cast as xs:float : "float",
               1 div 3 cast as xs:double : "double",
               1 div 3 cast as xs:integer : "integer"
             }

which asserts the following.
$result?((1 div 3 cast as xs:float)   cast as xs:decimal) eq "float"
$result?((1 div 3 cast as xs:double)  cast as xs:decimal) eq "double"
$result?((1 div 3 cast as xs:integer) cast as xs:decimal) eq "integer"


1 div 3 cast as xs:float has string value 0.33333334 and precise decimal 
value 0.33333 33432 67440 79589 84375.

1 div 3 cast as xs:double has string value 0.3333333333333333 and 
precise decimal value 0.33333 33333 33333 31482 96162 56247 39099 29394 
72198 48632 8125.

1 div 3 cast as xs:integer has string value 0.33....33 with an 
implementation-defined number of digits not fewer than 18.

Suppose that the implementation supports arbitrary precision decimals.  
Thus the effect of casting each of the above to decimal is identical to 
the precise decimal value, and the assertions will hold.

Suppose instead that the implementation supports xs:decimal with the 
mandatory minimum 18 digits.  Since the precise decimal value for 1 div 
3 cast as xs:double is 55 digits, it will be truncated at 18.   In this 
case,

(1 div 3 cast as xs:double)  cast as xs:decimal

and

(1 div 3 cast as xs:integer) cast as xs:decimal

have the same xs:decimal representation and the assertion

$result?((1 div 3 cast as xs:double)  cast as xs:decimal) eq "double"

no longer holds.

I propose that op:same-key be changed such that for numeric $k1 and $k2, 
true is returned only if

1. $k1 and $k2 are both subtypes of xs:double

2. $k1 and $k2 are both subtypes of xs:float

3. $k1 and $k2 are both subtypes of xs:decimal/xs:integer

(perhaps maintaining the special rules for +/-Infinity and NaN).

This is both simpler to compute (should maintaining a map really require 
computing a 55 digit key?), simpler to implement, avoids strange 
differences between implementations and avoids users getting sucked into 
the weird world of floating point representations.  There may well be 
use cases where it is desirable to be able to store a map containing 
both a 1 and 1e0 as different keys. The downside is that the user would 
need to use appropriately typed keys to perform lookup.  I'd argue that 
few users would expect

$result?(xs:decimal('0.333333333333333314829616256247390992939472198486328125')) 
would return 'double'

(and fewer still would be prepared to type it).

Regards,

     Tim

Received on Thursday, 2 June 2016 09:23:19 UTC