round()
ROUND 数字函数按指定的位数对提供的值进行舍入。
RoundingMode
-
ROUND_UP 向远离零的方向舍入。 总是在非零的舍弃尾数前面增大数字。 这种舍入方式从不会缩小计算结果的绝对
-
ROUND_DOWN
向零方向舍入。 从不在舍弃的尾数前面增大数字,即截断。 这种舍入方式从不会增大计算结果的绝对值。 -
ROUND_CEILING 向正无穷大方向舍入。 如果小数为正,将按照 ROUND_UP 方式舍入;如果小数为负,将按照ROUND_DOWN 方式舍入。 这种舍入方式从不会缩小计算出的值。
-
ROUND_FLOOR 向负无穷大方向舍入。 如果小数为正,将按照 ROUND_DOWN方式舍入;如果小数为负,将按照 ROUND_UP方式舍入。 这种舍入方式从不会增大计算出的值。
-
ROUND_HALF_UP 向“最接近的数字”舍入,只有在与两个相邻数字距离相等的情况下才按照 ROUND_UP 方式舍入。如果舍弃的尾数 >= 0.5,将按照ROUND_UP 方式舍入;否则按照 ROUND_DOWN 方式舍入。 这种舍入方式就是学校里通常讲的四舍五入。
-
ROUND_HALF_DOWN 向“最接近的数字”舍入,只有在与两个相邻数字距离相等的情况下才按照 ROUND_DOWN 方式舍入。 如果舍弃的尾数 > 0.5,将按照 ROUND_UP 方式舍入;否则按照 ROUND_DOWN 方式舍入。
-
ROUND_HALF_EVEN 向“最接近的数字”舍入,只有在与两个相邻数字的距离相等的情况下才向相邻的偶数舍入。如果被舍弃尾数左边的数字为奇数,将按照 ROUND_HALF_UP 方式舍入;如果为偶数,将按照 ROUND_HALF_DOWN方式舍入。在反复进行一系列计算时,这种舍入方式可以将累积误差减到最小。这种舍入方式有时也称为“银行家舍入法”。
默认方式 ROUND_HALF_EVEN
如果未指定 方式,那么将使用值 ROUND_HALF_EVEN。
Spark round 函数
https://spark.apache.org/docs/latest/api/sql/index.html#round
abstract class RoundBase(child: Expression, scale: Expression,
mode: BigDecimal.RoundingMode.Value, modeStr: String)
extends BinaryExpression with Serializable with ImplicitCastInputTypes with SupportQueryContext {
...
override lazy val dataType: DataType = child.dataType match {
case DecimalType.Fixed(p, s) =>
// After rounding we may need one more digit in the integral part,
// e.g. `ceil(9.9, 0)` -> `10`, `ceil(99, -1)` -> `100`.
val integralLeastNumDigits = p - s + 1
if (_scale < 0) {
// negative scale means we need to adjust `-scale` number of digits before the decimal
// point, which means we need at lease `-scale + 1` digits (after rounding).
val newPrecision = math.max(integralLeastNumDigits, -_scale + 1)
// We have to accept the risk of overflow as we can't exceed the max precision.
DecimalType(math.min(newPrecision, DecimalType.MAX_PRECISION), 0)
} else {
val newScale = math.min(s, _scale)
// We have to accept the risk of overflow as we can't exceed the max precision.
DecimalType(math.min(integralLeastNumDigits + newScale, 38), newScale)
}
case t => t
}
// not overriding since _scale is a constant int at runtime
def nullSafeEval(input1: Any): Any = {
dataType match {
case DecimalType.Fixed(p, s) =>
val decimal = input1.asInstanceOf[Decimal]
if (_scale >= 0) {
// Overflow cannot happen, so no need to control nullOnOverflow
decimal.toPrecision(decimal.precision, s, mode)
} else {
Decimal(decimal.toBigDecimal.setScale(_scale, mode), p, s)
}
case ByteType if ansiEnabled =>
MathUtils.withOverflow(
f = BigDecimal(input1.asInstanceOf[Byte]).setScale(_scale, mode).toByteExact,
context = getContextOrNull)
case ByteType =>
BigDecimal(input1.asInstanceOf[Byte]).setScale(_scale, mode).toByte
case ShortType if ansiEnabled =>
MathUtils.withOverflow(
f = BigDecimal(input1.asInstanceOf[Short]).setScale(_scale, mode).toShortExact,
context = getContextOrNull)
case ShortType =>
BigDecimal(input1.asInstanceOf[Short]).setScale(_scale, mode).toShort
case IntegerType if ansiEnabled =>
MathUtils.withOverflow(
f = BigDecimal(input1.asInstanceOf[Int]).setScale(_scale, mode).toIntExact,
context = getContextOrNull)
case IntegerType =>
BigDecimal(input1.asInstanceOf[Int]).setScale(_scale, mode).toInt
case LongType if ansiEnabled =>
MathUtils.withOverflow(
f = BigDecimal(input1.asInstanceOf[Long]).setScale(_scale, mode).toLongExact,
context = getContextOrNull)
case LongType =>
BigDecimal(input1.asInstanceOf[Long]).setScale(_scale, mode).toLong
case FloatType =>
val f = input1.asInstanceOf[Float]
if (f.isNaN || f.isInfinite) {
f
} else {
BigDecimal(f.toDouble).setScale(_scale, mode).toFloat
}
case DoubleType =>
val d = input1.asInstanceOf[Double]
if (d.isNaN || d.isInfinite) {
d
} else {
BigDecimal(d).setScale(_scale, mode).toDouble
}
}
}
/** Constructs a `BigDecimal` whose value is equal to that of the
* specified double value. Equivalent to `BigDecimal.decimal`.
*
* @param d the specified `Double` value
* @return the constructed `BigDecimal`
*/
def apply(d: Double): BigDecimal = decimal(d, defaultMathContext)
val defaultMathContext = MathContext.DECIMAL128
/**
* A {@code MathContext} object with a precision setting
* matching the IEEE 754R Decimal128 format, 34 digits, and a
* rounding mode of {@link RoundingMode#HALF_EVEN HALF_EVEN}, the
* IEEE 754R default.
*/
public static final MathContext DECIMAL128 =
new MathContext(34, RoundingMode.HALF_EVEN);
- DecimalType(precision: Int, scale: Int)
/**
* The data type representing `java.math.BigDecimal` values.
* A Decimal that must have fixed precision (the maximum number of digits) and scale (the number
* of digits on right side of dot).
*
* The precision can be up to 38, scale can also be up to 38 (less or equal to precision).
*
* The default precision and scale is (10, 0).
*
* Please use `DataTypes.createDecimalType()` to create a specific instance.
*
* @since 1.3.0
*/
@Stable
case class DecimalType(precision: Int, scale: Int) extends FractionalType {
DecimalType.checkNegativeScale(scale)
if (scale > precision) {
throw DataTypeErrors.decimalCannotGreaterThanPrecisionError(scale, precision)
}
if (precision > DecimalType.MAX_PRECISION) {
throw DataTypeErrors.decimalPrecisionExceedsMaxPrecisionError(
precision, DecimalType.MAX_PRECISION)
}