是否应该将 xs:double 转换为 xs:decimal 实现为 BigDecimal.valueOf(double



XQuery,与XSLT和XPath 2.0及更高版本共享,支持各种数字数据类型,其中两种是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。该类支持两种将double转换为BigDecimal的方法,即执行BigDecimal.valueOf(doubleValue)new BigDecimal(doubleValue)。根据 https://stackoverflow.com/a/7186298/252228 的说法,前者给出更直观的结果,而后者给出更正确的结果,例如BigDecimal.valueOf(1.1)结果1.1new BigDecimal(1.1)结果1.100000000000000088817841970012523233890533447265625

当我尝试用撒克逊人和存在来xs:doublexs: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),撒克逊和存在做new BigDecimal(1.1)

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

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 位必须基本如图所示。

撒克逊语中的实际代码是

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

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

但是,由于您暗示BigDecimal.valueOf(d)new BigDecimal(d)不等效,下一版本的 BaseX(版本 8.0)将返回更准确的结果。

最新更新