Округление чисел с заданной точностью¶
Задача¶
Требуется округлить число до заданного числа десятичных знаков после запятой. Однако функции 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
.