risingwave_expr_impl/scalar/
exp.rs1use num_traits::Zero;
16use risingwave_common::types::{Decimal, F64, FloatExt};
17use risingwave_expr::{ExprError, Result, function};
18
19fn err_logarithm_input() -> ExprError {
20 ExprError::InvalidParam {
21 name: "input",
22 reason: "cannot take logarithm of zero or a negative number".into(),
23 }
24}
25
26#[function("exp(float8) -> float8")]
27pub fn exp_f64(input: F64) -> Result<F64> {
28 if input.is_nan() {
31 Ok(input)
32 } else if input.is_infinite() {
33 if input.is_sign_negative() {
34 Ok(0.into())
35 } else {
36 Ok(input)
37 }
38 } else {
39 let res = input.exp();
40
41 if res.is_infinite() {
45 Err(ExprError::NumericOverflow)
46 } else if res.is_zero() {
47 Err(ExprError::NumericUnderflow)
48 } else {
49 Ok(res)
50 }
51 }
52}
53
54#[function("ln(float8) -> float8")]
55pub fn ln_f64(input: F64) -> Result<F64> {
56 if input.0 <= 0.0 {
57 return Err(err_logarithm_input());
58 }
59 Ok(input.ln())
60}
61
62#[function("log10(float8) -> float8")]
63pub fn log10_f64(input: F64) -> Result<F64> {
64 if input.0 <= 0.0 {
65 return Err(err_logarithm_input());
66 }
67 Ok(input.log10())
68}
69
70#[function("exp(decimal) -> decimal")]
71pub fn exp_decimal(input: Decimal) -> Result<Decimal> {
72 input.checked_exp().ok_or(ExprError::NumericOverflow)
73}
74
75#[function("ln(decimal) -> decimal")]
76pub fn ln_decimal(input: Decimal) -> Result<Decimal> {
77 input.checked_ln().ok_or_else(err_logarithm_input)
78}
79
80#[function("log10(decimal) -> decimal")]
81pub fn log10_decimal(input: Decimal) -> Result<Decimal> {
82 input.checked_log10().ok_or_else(err_logarithm_input)
83}
84
85#[cfg(test)]
86mod tests {
87 use risingwave_common::types::F64;
88 use risingwave_expr::ExprError;
89
90 use super::exp_f64;
91
92 #[test]
93 fn legal_input() {
94 let res = exp_f64(0.0.into()).unwrap();
95 assert_eq!(res, F64::from(1.0));
96 }
97
98 #[test]
99 fn underflow() {
100 let res = exp_f64((-1000.0).into()).unwrap_err();
101 match res {
102 ExprError::NumericUnderflow => (),
103 _ => panic!("Expected ExprError::FloatUnderflow"),
104 }
105 }
106
107 #[test]
108 fn overflow() {
109 let res = exp_f64(1000.0.into()).unwrap_err();
110 match res {
111 ExprError::NumericOverflow => (),
112 _ => panic!("Expected ExprError::FloatUnderflow"),
113 }
114 }
115
116 #[test]
117 fn nan() {
118 let res = exp_f64(f64::NAN.into()).unwrap();
119 assert_eq!(res, F64::from(f64::NAN));
120
121 let res = exp_f64((-f64::NAN).into()).unwrap();
122 assert_eq!(res, F64::from(-f64::NAN));
123 }
124
125 #[test]
126 fn infinity() {
127 let res = exp_f64(f64::INFINITY.into()).unwrap();
128 assert_eq!(res, F64::from(f64::INFINITY));
129
130 let res = exp_f64(f64::NEG_INFINITY.into()).unwrap();
131 assert_eq!(res, F64::from(0.0));
132 }
133}