xs:double 到 xs:decimal 的转换应该实现为 BigDecimal.valueOf(double) 还是 new BigDecimal(double)?

Should cast of xs:double to xs:decimal be implemented as BigDecimal.valueOf(double) or new BigDecimal(double)?

与 XSLT 和 XPath 2.0 及更高版本共享的 XQuery 支持各种数字数据类型,其中两种是 xs:doublexs:decimal。可以将 xs:double 转换为 xs:decimal,如 http://www.w3.org/TR/xquery-operators/#casting-to-numerics 中所定义。

在 Java 中完成的实现似乎使用 Java double 数据类型实现 xs:double,使用 java.math.BigDecimal [=] 实现 xs:decimal 51=]。 class 支持两种将 double 转换为 BigDecimal 的方法,即 BigDecimal.valueOf(doubleValue)new BigDecimal(doubleValue)。根据,前者给出更直观的结果而后者给出更正确的结果,例如BigDecimal.valueOf(1.1)导致1.1new BigDecimal(1.1)导致[=29] =].

当我尝试使用 Saxon 和 Exist 将 xs:double 转换为 xs:decimal

xquery version "1.0";

let $d1 as xs:double := 1.1E0
return xs:decimal($d1)

输出 1.100000000000000088817841970012523233890533447265625 而使用 BaseX 它输出 1.1。我想差异是由不同的实现造成的,BaseX 做 BigDecimal.valueOf(1.1),Saxon 和 Exist 做 new BigDecimal(1.1).

我的问题是:根据http://www.w3.org/TR/xquery-operators/#casting-to-numerics,哪种方法是实施转换操作的正确方法?

XQuery Recommendation 将 double 值最接近的十进制表示形式留给了实现。原因是规范应该支持任意编程语言的实现。

但是,由于您提示 BigDecimal.valueOf(d)new BigDecimal(d) 不等同,下一个版本的 BaseX(版本 8.0)将 return 得到更准确的结果。

xs:decimal 的实现需要支持至少 18 位有效的十进制数字,如果这样做,最接近 xs:double 值 1.1 的 xs:decimal 将类似于1.100 000 000 000 000 088 而不是 1.1。 (实际上是 19 位而不是 18 位,但即使是 18 位,与 1.1 的差异也应该显示出来。)所以我认为返回小数 1.1 是不符合要求的。位数是实现定义的,超过 18 位,但前 18 位必须基本如图所示。

Saxon 中的实际代码是

public DecimalValue(double in) throws ValidationException {
        try {
            BigDecimal d = new BigDecimal(in);
            value = d.stripTrailingZeros();
        } catch (NumberFormatException err) {
            //...
        }