Должно ли приведение xs: double к xs: decimal быть реализовано как BigDecimal.valueOf (double) или new BigDecimal (double)?

XQuery, совместно используемый с XSLT и XPath 2.0 и более поздними версиями, поддерживает различные числовые типы данных, два из которых - xs:double и xs:decimal. Можно преобразовать xs:double в xs:decimal, как определено в http://www.w3.org/TR/xquery-operators/#casting-to-numerics.

Реализации, выполненные на Java, похоже, реализуют xs:double с использованием типа данных Java double и xs:decimal с использованием класса java.math.BigDecimal. Этот класс поддерживает два способа преобразования double в BigDecimal, а именно выполнение BigDecimal.valueOf(doubleValue) и new BigDecimal(doubleValue). Согласно https://stackoverflow.com/a/7186298/252228, первое дает более интуитивный результат, а второе дает более правильный результат, например, BigDecimal.valueOf(1.1) дает 1.1, а new BigDecimal(1.1) дает 1.100000000000000088817841970012523233890533447265625.

Когда я пробую преобразовать xs:double в xs:decimal с Saxon и Exist, тогда

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?


person Martin Honnen    schedule 01.02.2015    source источник
comment
Я бы сказал, что в любом случае верен, а также все реализации правильно реализуют спецификацию. Там написано If ST is xs:float or xs:double, then TV is the xs:decimal value, within the set of xs:decimal values that the implementation is capable of representing, that is numerically closest to SV, и я бы сказал, что оба возвращают самое близкое численное значение, которое процессор может обработать.   -  person dirkk    schedule 02.02.2015


Ответы (2)


Требуется реализация xs: decimal для поддержки по крайней мере 18 значащих десятичных цифр, и если это так, ближайшим xs: decimal к значению xs: double 1.1 будет что-то вроде 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) {
            //...
        }
person Michael Kay    schedule 02.02.2015
comment
Я не совсем понимаю. Если в спецификации указано не менее 18 значащих десятичных цифр, почему возврат 1.100 000 000 000 000 000 (который может быть сокращен до 1.1 без потери значимого числа) будет неправильным? - person dirkk; 03.02.2015
comment
Я бы не сказал, что это так. 1.1 и 1.100 000 000 000 000 000 - это просто разные представления одного и того же числа, поэтому, если вы на самом деле не возвращаете ничего другого. Я сказал, что числовое значение двойного 1.1e0 не то же самое, что десятичное 1.1, и если вы удерживаете десятичные дроби до 18 или более цифр, тогда разница проявится. - person Michael Kay; 03.02.2015
comment
@MichaelKay, будет ли format-number(xs:decimal(1.1E0), '0.00000000000000000') eq '1.10000000000000009' тестовым примером, который должна пройти реализация XQuery 3.0, если она реализует xs:decimal с хотя бы необходимыми 18 значащими цифрами? - person Martin Honnen; 04.02.2015
comment
@MartinHonnen, да, я думаю, что это был бы законный тест, хотя мой аппетит к включению крайних случаев в набор тестов уменьшается из-за количества дискуссий, которые они, как правило, вызывают ... - person Michael Kay; 04.02.2015

Рекомендация XQuery оставляет на усмотрение реализации, каким должно быть ближайшее десятичное представление значения типа double. Причина в том, что спецификация должна поддерживать реализации на произвольных языках программирования.

Однако благодаря вашему намеку на то, что BigDecimal.valueOf(d) и new BigDecimal(d) не эквивалентны, следующий выпуск BaseX (версия 8.0) вернет более точный результат.

person Christian Grün    schedule 02.02.2015