2015-10-23 3 views
0

Существует очень странная проблема, с которой мы сталкиваемся с округлением XSLT и функциями Format-number. Допустим, у меня есть номер 131.855, и я хочу округлить его до двух знаков после запятой. Я ожидаю, что ответ будет 131,86, но функция XSLT round() округляет его до 131,85. Я попытался использовать «round (131.855 * 100) div 100», но он не работает. Если мне нужно округлить число, например 127.855, оно округляется правильно до 127.86, используя тот же код, т. Е. «Round (127.855 * 100) div 100». Кроме того, странно, если я попытаюсь округлить 131.755, он округляется до 131.76! Очень странно. Мы также пробовали использовать функцию format-number(), но это также дает странные результаты. Например, если я беру номер 349615.225, и я использую номер формата на этом i.e-формате (349615.225, '#. ##'), он дает 349615.22, тогда как я ожидаю, что десятичные числа будут .23. Но если я использую формат-номер на 131.855 он автоматически преобразуется в 131.86 ...Вопросы округления XSLT

Я также попытался с помощью круглой функции() внутри-формата числа(), но это также дало аналогичные результаты ..

Мы используем XSLT 1.0. Переход на XSLT 2.0 кажется сложной задачей. Только обходной путь, который я вижу, - использовать некоторую функцию java и вызывать ее из XSL для округления.

Любые идеи будут высоко оценены.

Edit:

Как ни странно точно такое же проблема возникает с функцией Math.Round Java.

+0

Какой процессор XSLT вы используете? –

+0

Это, по-видимому, ошибка, вызванная арифметикой с плавающей запятой. Мне удалось воспроизвести проблему как в Xalan http://xsltransform.net/bFN1y8S, так и в Saxon http://xsltransform.net/bFN1y8S/1, но с любопытством не в libxslt, так что это может быть проблема с движком Java. –

+0

"* То же самое происходит с функцией Java Math.round. *« Ну, вот и все. –

ответ

1

Вы можете использовать следующее:

format-number(round(100 * $number) div 100, '#.00')

round() функция округляет число до ближайшего целого числа, а просто использование round() не может округлить число правильно.
format-number() форматирует число путем обрезки данных (я думаю), что может привести к потере стоимости.
Использование как round(), так и format-number() должно влиять на работу.

Ниже приведен пример различных видов поведения.

Вход:

<root>5.225</root> 

XSLT:

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
    <xsl:output method="text" /> 
    <xsl:template match="/"> 
     <xsl:value-of select="round(*)"/> 
     <xsl:text>&#xa;</xsl:text> 
     <xsl:value-of select="round(100 * *)"/> 
     <xsl:text>&#xa;</xsl:text> 
     <xsl:value-of select="format-number(*, '#.00')"/> 
     <xsl:text>&#xa;</xsl:text> 
     <xsl:value-of select="format-number(round(100 * *) div 100, '#.00')"/> 
    </xsl:template> 
</xsl:transform> 

Выход:
5,22
5,23

+0

"* Функция round() округляет число до ближайшего четного числа, *« Нет, округляется до ближайшего целого числа, и оно всегда округляет половину ** вверх **. - «* Формат-формат() форматирует число путем обрезки данных, *« Поведение функции не определено в спецификации, и вы обнаружите, что разные процессоры реализуют его по-разному (хотя я не знаю который усекает). –

+0

Да, я должен был быть осторожным, когда я сказал «даже» :) Позвольте мне уточнить мой ответ. «Формат-номер()», было моим предположением, кстати, он ведет себя. Спасибо @ michael.hor257k! –

+0

Мы пробовали эту опцию также на 131.855, но она не работает. Для тестирования я использую процессор XSLT по умолчанию в Eclipse. –

0

Первое, что нужно понимать, что когда вы пишете число например 131,855, фактическое значение, которое оно представляет, не является точно на полпути между 131,85 и 131,86. Число чисел с плавающей запятой двойной точности не равно 131,855, поэтому фактическое значение, которое вы используете, немного ниже этого или немного выше. Эта неточность возникает, как только вы записываете число вниз, оно возникает не только тогда, когда вы выполняете арифметику. Когда вы умножаете его на 100, эта разница увеличивается, и когда вы используете round(), она переходит к ближайшему целому числу, которое будет зависеть от того, было ли приближение вверх или вниз в первую очередь. Поэтому, учитывая, что XSLT 1.0 предлагает только числа с плавающей запятой, нет способа избежать такой проблемы.

В XSLT 2.0 вы можете использовать десятичные числа, которые ведут себя так, как люди ожидают.

+0

. Тогда почему 127.855 округляет до 127.86 и 131.755 округляет до 131.76? –

+0

Это непредсказуемо, будет ли число, которое вы получите, выше или ниже числа, которое вы пишете. В моей системе, когда я пишу 127.855, число, которое я получаю, составляет 127.8550000000000039790393202565610408782958984375, тогда как когда я пишу 131.755, число, которое я получаю, составляет 131.7549999999999954525264911353588104248046875 –

Смежные вопросы