Job Board
Consulting

Spark Scala Round Functions: round and bround

The round and bround functions round numeric columns to a given number of decimal places. They differ in how they handle exact halves: round rounds half away from zero (the most common convention), while bround uses banker's rounding, which rounds half to the nearest even number to reduce bias in large aggregations.

round

The round function rounds a numeric column using HALF_UP mode — values exactly halfway between two integers are rounded away from zero. It has two signatures:

def round(e: Column): Column

def round(e: Column, scale: Int): Column

The single-argument form rounds to zero decimal places (i.e., to the nearest integer, but the result is still a floating-point type). Pass a scale to round to a specific number of decimal places. A negative scale rounds to the left of the decimal point — so scale = -1 rounds to the nearest 10.

val df = Seq(
  3.14159,
  2.5,
  -2.5,
  1.49,
  99.999,
).toDF("value")

val df2 = df
  .withColumn("rounded", round(col("value")))

df2.show(false)
// +-------+-------+
// |value  |rounded|
// +-------+-------+
// |3.14159|3.0    |
// |2.5    |3.0    |
// |-2.5   |-3.0   |
// |1.49   |1.0    |
// |99.999 |100.0  |
// +-------+-------+

Notice that 2.5 rounds to 3.0 and -2.5 rounds to -3.0 — both move away from zero. This is the rounding convention most people learn in school.

Using the second signature, you can round to any number of decimal places, and a negative scale rounds to a power of ten on the left side of the decimal:

val df = Seq(
  ("apples", 12.3456),
  ("bananas", 7.8912),
  ("cherries", 0.005),
  ("dates", 99.9999),
  ("elderberries", -3.14159),
).toDF("item", "price")

val df2 = df
  .withColumn("price_2dp", round(col("price"), 2))
  .withColumn("price_0dp", round(col("price"), 0))
  .withColumn("price_neg1", round(col("price"), -1))

df2.show(false)
// +------------+--------+---------+---------+----------+
// |item        |price   |price_2dp|price_0dp|price_neg1|
// +------------+--------+---------+---------+----------+
// |apples      |12.3456 |12.35    |12.0     |10.0      |
// |bananas     |7.8912  |7.89     |8.0      |10.0      |
// |cherries    |0.005   |0.01     |0.0      |0.0       |
// |dates       |99.9999 |100.0    |100.0    |100.0     |
// |elderberries|-3.14159|-3.14    |-3.0     |0.0       |
// +------------+--------+---------+---------+----------+

bround

The bround function uses banker's rounding (HALF_EVEN mode): values that fall exactly halfway between two possibilities are rounded toward the nearest even number. It has the same two signatures as round:

def bround(e: Column): Column

def bround(e: Column, scale: Int): Column

Banker's rounding eliminates the upward bias that HALF_UP introduces when summing many half-values, which makes it the preferred choice for financial calculations and statistical work where rounding bias can accumulate.

The contrast between the two functions is clearest at the .5 boundary:

val df = Seq(
  0.5,
  1.5,
  2.5,
  3.5,
  -0.5,
  -1.5,
  -2.5,
).toDF("value")

val df2 = df
  .withColumn("round", round(col("value")))
  .withColumn("bround", bround(col("value")))

df2.show(false)
// +-----+-----+------+
// |value|round|bround|
// +-----+-----+------+
// |0.5  |1.0  |0.0   |
// |1.5  |2.0  |2.0   |
// |2.5  |3.0  |2.0   |
// |3.5  |4.0  |4.0   |
// |-0.5 |-1.0 |0.0   |
// |-1.5 |-2.0 |-2.0  |
// |-2.5 |-3.0 |-2.0  |
// +-----+-----+------+

Look at 0.5 and 2.5: round produces 1.0 and 3.0 (away from zero), while bround produces 0.0 and 2.0 (toward the nearest even integer). For 1.5 and 3.5, both functions agree because the "round up" target is already even.

Banker's Rounding at Non-Integer Scales

The same HALF_UP vs HALF_EVEN distinction applies when rounding to a non-integer scale. Here's the same pattern at two decimal places:

val df = Seq(
  1.235,
  1.245,
  1.255,
  1.265,
  2.345,
).toDF("value")

val df2 = df
  .withColumn("round_2dp", round(col("value"), 2))
  .withColumn("bround_2dp", bround(col("value"), 2))

df2.show(false)
// +-----+---------+----------+
// |value|round_2dp|bround_2dp|
// +-----+---------+----------+
// |1.235|1.24     |1.24      |
// |1.245|1.25     |1.24      |
// |1.255|1.26     |1.26      |
// |1.265|1.27     |1.26      |
// |2.345|2.35     |2.34      |
// +-----+---------+----------+

Look at 1.245: round gives 1.25 (away from zero) while bround gives 1.24 (the nearest even digit). For 1.255, both agree on 1.26 because 6 is already even. For 2.345, round produces 2.35 and bround rounds down to 2.34.

If exact decimal rounding matters — currency calculations, regulated financial reporting — store the column as DecimalType rather than Double so the value being rounded is exact. With Double, a literal like 1.235 is actually stored as something close to but not exactly 1.235, which can occasionally make the rounded result diverge from what you'd expect on paper.

For absolute value, see abs. To format a number as a string with a fixed number of decimal places and a thousands separator, see format_number.

Example Details

Created: 2026-05-21 10:43:06 PM

Last Updated: 2026-05-21 10:43:06 PM