Главная » XSLT » Округление чисел с заданной точностью

1

Задача

Требуется округлить число до заданного числа десятичных знаков после за­пятой. Однако функции XSLT round, ceiling и floor всегда возвращают це­лое число.

10.00   =    1 •

3.50   =        Г.

4.44   =          t.

77.78   =   V V

-8.80   =      -Л

1.00  =     1 .

444.00   =  ? 4

1.12 =    1 .

7.77   =        V.

3.14   =         г.

10.00   =    1 •

9.00   =       Я .

8.00  =      Л.

7.00   =        V.

666.00   =   11

5555.00 =          о, ооо. >’

-4444444.00 = -1, ???^???. – -

22.33   =  ТХ.ТГ

18.00  =      U."

36.54   =     VI. о*

43.00   =   t X. • •

99999.00 =       14,441. • •

999999.00 =     111,111.*-

9999999.00 =  1,111,111.•>

32.00   =     ГХ. * •

64.00   =

-64.00   =     -М.

Решение

XSLT 1.0

Умножим          на 10 в степени n, где n – требуемое число десятичных знаков, затем округлим и разделим на тот же коэффициент. Предположим, что $pi = = 3/141592 653 5897 932. Тогда вычисление выражения

’round($pi * 10000) div 10000′

<xsl:value-of select=

дает 3.1416. Аналогично:

<xsl:value-of select="ceiling($pi * 10000) div 10000"

дает 3.1416, а:

<xsl:value-of select="floor($pi * 10000) div 10000"/>

дает 3.1415.

Округлить до заданного числа знаков можно также с помощью функции

format-number():

<xsl:value-of select="format-number($pi, ‘#.####’)"/>

Получится 3.1416. Это решение будет работать, даже если в целой части всего одна значащая цифра, поскольку функция format-number никогда не интер­претирует спецификацию формата как указание удалять значащие цифры из це­лой части:

<xsl:value-of select="format-number($pi * 100, ‘#.####’)"/>

В результате получаем 314.1593.

С помощью функции format-number можно получить эффект отбрасыва­ния вместо округления, если задать в форматной строке на одну цифру больше, чем необходимо, а затем отбросить последний символ:

<xsl:variable name="pi-to-5-sig" select="format-number($pi, ‘#.#####’)"/>

<xsl:value-of select="substring($pi-to-5-sig,1, string-length($pi-to-5-sig) – 1"/>

Результат будет равен 3.1415.

XSLT 2.0

В большинстве приложений задачу может решить появившаяся в XPath 2.0 функция round-half-to-even(). Half to even (округление половины до четного) означает, что в случае, когда округляемая величина оказывается точ­но посередине между большим и меньшим значением, округление производит­ся в том направлении, где получится четный результат. Так, round-half- to-even(1.115,2) eq 1.12, и round-half-to-even(1.125,2) eq 1.12! В первом случае мы округляем с избытком, поскольку 2 – четное число, а во вто­ром – с недостатком, так как 3 – число нечетное. Теоретически такой метод обосно­вывается тем, что если имеется много чисел, то округление с избытком должно про­исходить примерно так же часто, как с недостатком, поэтому ошибки округления будут взаимно уничтожаться. Вы, конечно, догадались, что второй аргумент функ­ции round-half-to-even() – число десятичных знаков после округления.

Если в вашем приложении требуется, чтобы число, оканчивающееся на 5, все­гда округлялось с избытком, то можете воспользоваться техникой, описанной в рецепте для XSLT 1.0.

Обсуждение

Метод «умножение, округление, деление» хорошо работает, если все проме­жуточные результаты не выходят за пределы представимости числа с плавающей точкой в формате IEEE. Если вы попробуете сохранить слишком много знаков после запятой, то результат будет искажен вследствие правил работы с числами с плавающей точкой. Например, попытка получить 16 десятичных знаков числа п даст всего 15:

<xsl:value-of select="round($pi * 10000000000000000) div 10000000000000000"/>

В результате получим 3.141592653589793, а не 3.1415926535897932. Альтернативное решение – обращаться с числом, как со строкой, а затем обре­зать лишние цифры:

<xsl:value-of select="concat(substring-before($pi,’.’), substring(substring-after($pi,’.’),1,4))"/>

дает 3.1415.

Этот прием позволяет добиться того же эффекта, что ceiling или round, но ценой дополнительной сложности:

<xsl:variable name="whole" select="substring-before($pi,’.’)"/> <xsl:variable name="frac" select="substring-after($pi,’.’)"/> <xsl:value-of select="concat($whole,

substring($frac,1,3)), round(substring($frac,4,2) div 10))"/>

В результате получаем 3.1416.

Мангано Сэл  XSLT. Сборник рецептов. – М.: ДМК Пресс, СПБ.: БХВ-Петербург, 2008. – 864 с.: ил.

По теме:

  • Комментарии

1 комментарий

  1. hello says:

    С помощью функции format-number можно получить эффект отбрасыва­ния вместо округления, если задать в форматной строке на одну цифру больше, чем необходимо, а затем отбросить последний символ:
    попробуй 0,999999:) получишь 1!