#Numeric Functions

XPath's numeric functions cover rounding, absolute values, and aggregate operations over sequences. If you're used to System.Math and LINQ aggregates in C#, these map directly.

#Contents


#Rounding and Truncation

#round()

Rounds a number to the nearest integer, or to a specified number of decimal places.

Signature: round($value as xs:numeric?) as xs:numeric? Signature (XPath 3.1+): round($value as xs:numeric?, $precision as xs:integer) as xs:numeric?

round(3.7)        => 4
round(3.3)        => 3
round(3.5)        => 4        (: rounds half up :)
round(-3.5)       => -3       (: rounds half toward positive infinity :)
round(3.14159, 2) => 3.14
round(1234, -2)   => 1200     (: negative precision rounds to tens, hundreds, etc. :)

C# equivalent: Math.Round(3.7) — but note C# uses "round half to even" (banker's rounding) by default, while XPath rounds half up.

Value

XPath round()

C# Math.Round()

2.5

3

2 (banker's rounding)

3.5

4

4 (banker's rounding)

-2.5

-2

-2

To get XPath-style rounding in C#, use Math.Round(value, MidpointRounding.AwayFromZero).


#round-half-to-even()

Rounds using banker's rounding (round half to nearest even number). This minimizes cumulative rounding bias.

Signature: round-half-to-even($value as xs:numeric?, $precision as xs:integer?) as xs:numeric?

round-half-to-even(2.5)      => 2       (: rounds to even :)
round-half-to-even(3.5)      => 4       (: rounds to even :)
round-half-to-even(2.45, 1)  => 2.4
round-half-to-even(2.55, 1)  => 2.6

C# equivalent: Math.Round(2.5) — this is C#'s default rounding mode.

When to use: Financial calculations where rounding bias accumulates over many operations.


#floor()

Rounds down to the nearest integer (toward negative infinity).

Signature: floor($value as xs:numeric?) as xs:numeric?

floor(3.7)    => 3
floor(3.2)    => 3
floor(-3.2)   => -4      (: toward negative infinity, not toward zero! :)
floor(-3.7)   => -4

C# equivalent: Math.Floor(3.7)


#ceiling()

Rounds up to the nearest integer (toward positive infinity).

Signature: ceiling($value as xs:numeric?) as xs:numeric?

ceiling(3.2)   => 4
ceiling(3.7)   => 4
ceiling(-3.2)  => -3     (: toward positive infinity :)
ceiling(-3.7)  => -3

C# equivalent: Math.Ceiling(3.2)

Practical example — calculating pages needed:

ceiling(count(//item) div 10)   (: number of pages with 10 items per page :)

#Absolute Value

#abs()

Returns the absolute value of a number.

Signature: abs($value as xs:numeric?) as xs:numeric?

abs(-5)     => 5
abs(5)      => 5
abs(-3.14)  => 3.14
abs(0)      => 0

C# equivalent: Math.Abs(-5)

Practical example — finding the magnitude of a difference:

abs(//actual - //expected)   (: deviation regardless of direction :)

#Aggregation

These functions operate on sequences — the XPath equivalent of LINQ aggregate methods.

#sum()

Returns the sum of a sequence of numbers.

Signature: sum($values as xs:anyAtomicType*, $zero as xs:anyAtomicType?) as xs:anyAtomicType

sum((1, 2, 3, 4, 5))           => 15
sum(//item/price)               => total of all prices
sum(//order/@amount)            => total of all order amounts
sum(())                         => 0        (: empty sequence :)
sum((), 0.00)                   => 0.00     (: with explicit zero value :)

C# equivalent: items.Sum() or items.Sum(x => x.Price)

Given this XML:

<order>
  <item><price>9.99</price><qty>2</qty></item>
  <item><price>24.50</price><qty>1</qty></item>
  <item><price>4.99</price><qty>3</qty></item>
</order>
sum(/order/item/price)     => 39.48

Note: To sum products (price × quantity), you need a for expression or sum(for $i in //item return $i/price * $i/qty).


#avg()

Returns the average of a sequence of numbers.

Signature: avg($values as xs:anyAtomicType*) as xs:anyAtomicType?

avg((1, 2, 3, 4, 5))     => 3
avg(//item/price)          => average price
avg(())                    => ()    (: empty sequence returns empty :)

C# equivalent: items.Average()


#min()

Returns the minimum value in a sequence.

Signature: min($values as xs:anyAtomicType*, $collation as xs:string?) as xs:anyAtomicType?

min((3, 1, 4, 1, 5))                      => 1
min(//item/price)                           => lowest price
min(//order/@date)                          => earliest date (works with xs:date!)
min(("banana", "apple", "cherry"))         => "apple" (: string comparison :)

C# equivalent: items.Min()

Note: min() works with dates, strings, and numbers — unlike C#'s Min() which needs IComparable.


#max()

Returns the maximum value in a sequence.

Signature: max($values as xs:anyAtomicType*, $collation as xs:string?) as xs:anyAtomicType?

max((3, 1, 4, 1, 5))        => 5
max(//item/price)             => highest price
max(//order/@date)            => most recent date

C# equivalent: items.Max()


#count()

Returns the number of items in a sequence.

Signature: count($values as item()*) as xs:integer

count((1, 2, 3))              => 3
count(//book)                  => number of book elements
count(//book[@category='data']) => number of data books
count(())                      => 0

C# equivalent: items.Count() or .Length

Practical example — conditional based on count:

if (count(//error) > 0) then "Errors found" else "All clear"

#Numeric Testing

#is-NaN()

Tests whether a value is NaN (Not a Number). New in XPath 4.0.

Signature: is-NaN($value as xs:anyAtomicType) as xs:boolean

is-NaN(xs:double('NaN'))       => true
is-NaN(42)                     => false
is-NaN(0 div 0.0e0)            => true

C# equivalent: double.IsNaN(value)

Why this exists: The expression $x = $x returns false when $x is NaN (IEEE 754 behavior), which is counterintuitive. is-NaN() is the explicit test.