Job Board
Consulting

Spark Scala Ceil, Floor, and Rint

The ceil, floor, and rint functions round a numeric column to an integer. ceil rounds up toward positive infinity, floor rounds down toward negative infinity, and rint rounds to the nearest integer using banker's rounding for exact halves. ceil and floor also accept a scale argument to round to a specific number of decimal places.

ceil and floor

ceil returns the smallest integer that is greater than or equal to the input. floor returns the largest integer that is less than or equal to the input. Both have three signatures:

def ceil(e: Column): Column

def ceil(columnName: String): Column

def ceil(e: Column, scale: Column): Column

The floor signatures mirror these exactly. Without a scale, the result is a long representing the rounded integer. With a scale, the result preserves the column's numeric type at the specified number of decimal places.

val df = Seq(
  3.14,
  2.5,
  -2.5,
  -3.7,
  0.0,
  99.001,
).toDF("value")

val df2 = df
  .withColumn("ceil", ceil(col("value")))
  .withColumn("floor", floor(col("value")))

df2.show(false)
// +------+----+-----+
// |value |ceil|floor|
// +------+----+-----+
// |3.14  |4   |3    |
// |2.5   |3   |2    |
// |-2.5  |-2  |-3   |
// |-3.7  |-3  |-4   |
// |0.0   |0   |0    |
// |99.001|100 |99   |
// +------+----+-----+

Note that ceil(-2.5) is -2, not -3ceil always rounds toward positive infinity, which for negative numbers means rounding closer to zero. Likewise, floor(-2.5) is -3 because floor rounds toward negative infinity. This is the standard mathematical definition and differs from round, which rounds half away from zero regardless of sign.

Rounding to a Specific Scale

The ceil and floor overloads that take a scale argument first appeared in version 3.3.0 and are defined as:

def ceil(e: Column, scale: Column): Column

def floor(e: Column, scale: Column): Column

The scale is a Column, not an Int, so pass a literal with lit. A positive scale rounds to that many decimal places; a negative scale rounds to a power of ten to the left of the decimal point.

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

val df2 = df
  .withColumn("ceil_2dp", ceil(col("price"), lit(2)))
  .withColumn("floor_2dp", floor(col("price"), lit(2)))
  .withColumn("ceil_neg1", ceil(col("price"), lit(-1)))
  .withColumn("floor_neg1", floor(col("price"), lit(-1)))

df2.show(false)
// +------------+--------+--------+---------+---------+----------+
// |item        |price   |ceil_2dp|floor_2dp|ceil_neg1|floor_neg1|
// +------------+--------+--------+---------+---------+----------+
// |apples      |12.3456 |12.35   |12.34    |20       |10        |
// |bananas     |7.8912  |7.90    |7.89     |10       |0         |
// |cherries    |0.005   |0.01    |0.00     |10       |0         |
// |dates       |-3.14159|-3.14   |-3.15    |0        |-10       |
// |elderberries|99.9999 |100.00  |99.99    |100      |90        |
// +------------+--------+--------+---------+---------+----------+

Look at dates with price = -3.14159: ceil_2dp is -3.14 (toward positive infinity) and floor_2dp is -3.15 (toward negative infinity). At a negative scale of -1, ceil of 0.005 rounds up to the nearest 10 — which is 10 — while floor rounds down to 0.

rint

The rint function rounds a Double column to the nearest integer-valued Double. For exact halves, it uses banker's rounding (HALF_EVEN), rounding to the nearest even integer.

def rint(e: Column): Column

def rint(columnName: String): Column

Unlike ceil and floor, which return a long, rint returns a Double whose value is mathematically an integer. This matches the semantics of Java's Math.rint.

val df = Seq(
  2.5,
  -2.5,
  2.4,
  2.6,
  -2.4,
  -2.6,
  0.0,
).toDF("value")

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

df2.show(false)
// +-----+----+
// |value|rint|
// +-----+----+
// |2.5  |2.0 |
// |-2.5 |-2.0|
// |2.4  |2.0 |
// |2.6  |3.0 |
// |-2.4 |-2.0|
// |-2.6 |-3.0|
// |0.0  |0.0 |
// +-----+----+

Both 2.5 and -2.5 round to 2.0 and -2.0 because 2 is the nearest even integer in each case. Non-halves like 2.6 and -2.6 round to 3.0 and -3.0 — the nearest integer in the usual sense. If you want HALF_UP behavior instead, use round.

Comparing All Three

Lining up ceil, floor, and rint against the same set of half-values shows how each function behaves at the boundary:

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

val df2 = df
  .withColumn("ceil", ceil(col("value")))
  .withColumn("floor", floor(col("value")))
  .withColumn("rint", rint(col("value")))

df2.show(false)
// +-----+----+-----+----+
// |value|ceil|floor|rint|
// +-----+----+-----+----+
// |1.5  |2   |1    |2.0 |
// |2.5  |3   |2    |2.0 |
// |3.5  |4   |3    |4.0 |
// |4.5  |5   |4    |4.0 |
// |-1.5 |-1  |-2   |-2.0|
// |-2.5 |-2  |-3   |-2.0|
// |-3.5 |-3  |-4   |-4.0|
// +-----+----+-----+----+

ceil and floor always disagree by 1 for any non-integer input. rint lands on whichever of the two is even — 1.5 → 2, 2.5 → 2, 3.5 → 4, 4.5 → 4 — so the result alternates with the input's neighbor parity rather than always rounding up.

For HALF_UP rounding and banker's rounding to a specified scale, see round and bround. For absolute value, see abs.

Example Details

Created: 2026-05-23 10:05:25 PM

Last Updated: 2026-05-23 10:05:25 PM