Округление чисел с заданной точностью¶
Задача¶
Требуется округлить число до заданного числа десятичных знаков после запятой. Однако функции XSLT round, ceiling и floor всегда возвращают целое число.
Решение¶
XSLT 1.0¶
Умножим на 10 в степени n, где n - требуемое число десятичных знаков, затем округлим и разделим на тот же коэффициент. Предположим, что $pi = 3.1415926535897932. Тогда вычисление выражения
1 | |
дает 3.1416. Аналогично:
1 | |
дает 3.1416, а:
1 | |
дает 3.1415.
Округлить до заданного числа знаков можно также с помощью функции format-number():
1 | |
Получится 3.1416. Это решение будет работать, даже если в целой части всего одна значащая цифра, поскольку функция format-number никогда не интерпретирует спецификацию формата как указание удалять значащие цифры из целой части:
1 | |
В результате получаем 314.1593.
С помощью функции format-number можно получить эффект отбрасывания вместо округления, если задать в форматной строке на одну цифру больше, чем необходимо, а затем отбросить последний символ:
1 2 | |
Результат будет равен 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:
1 2 3 | |
В результате получим 3.141592653589793, а не 3.1415926535897932.
Альтернативное решение – обращаться с числом, как со строкой, а затем обрезать лишние цифры:
1 2 3 | |
дает 3.1415.
Этот прием позволяет добиться того же эффекта, что ceiling или round, но ценой дополнительной сложности:
1 2 3 | |
В результате получаем 3.1416.