MCPcopy Create free account
hub / github.com/apache/datafusion / pow_decimal_int

Function pow_decimal_int

datafusion/functions/src/math/power.rs:126–188  ·  view source on GitHub ↗

Binary function to calculate a math power to integer exponent for scaled integer types. Formula The power for a scaled integer `b` is ```text (b * 10^(-s)) ^ e ``` However, the result should be scaled back from scale 0 to scale `s`, which is done by multiplying by `10^s`. At the end, the formula is: ```text b^e * 10^(-s * e) * 10^s = b^e / 10^(s * (e-1)) ``` Example of 2.5 ^ 4 = 39: 2.5 is repr

(base: T, scale: i8, exp: i64)

Source from the content-addressed store, hash-verified

124/// The unscaled result is 25^4 = 390625
125/// Scale it back to 1: 390625 / 10^4 = 39
126fn pow_decimal_int<T>(base: T, scale: i8, exp: i64) -> Result<T, ArrowError>
127where
128 T: ArrowNativeType + ArrowNativeTypeOp + ToPrimitive + NumCast + Copy,
129{
130 // Negative exponent: fall back to float computation
131 if exp < 0 {
132 return pow_decimal_float(base, scale, exp as f64);
133 }
134
135 let exp: u32 = exp.try_into().map_err(|_| {
136 ArrowError::ArithmeticOverflow(format!("Unsupported exp value: {exp}"))
137 })?;
138 // Handle edge case for exp == 0
139 // If scale < 0, 10^scale (e.g., 10^-2 = 0.01) becomes 0 in integer arithmetic.
140 if exp == 0 {
141 return if scale >= 0 {
142 T::usize_as(10).pow_checked(scale as u32).map_err(|_| {
143 ArrowError::ArithmeticOverflow(format!(
144 "Cannot make unscale factor for {scale} and {exp}"
145 ))
146 })
147 } else {
148 Ok(T::ZERO)
149 };
150 }
151 let powered: T = base.pow_checked(exp).map_err(|_| {
152 ArrowError::ArithmeticOverflow(format!("Cannot raise base {base:?} to exp {exp}"))
153 })?;
154
155 // Calculate the scale adjustment: s * (e - 1)
156 // We use i64 to prevent overflow during the intermediate multiplication
157 let mul_exp = (scale as i64).wrapping_mul(exp as i64 - 1);
158
159 if mul_exp == 0 {
160 return Ok(powered);
161 }
162
163 // If mul_exp is positive, we divide (standard case).
164 // If mul_exp is negative, we multiply (negative scale case).
165 if mul_exp > 0 {
166 let div_factor: T =
167 T::usize_as(10).pow_checked(mul_exp as u32).map_err(|_| {
168 ArrowError::ArithmeticOverflow(format!(
169 "Cannot make div factor for {scale} and {exp}"
170 ))
171 })?;
172 powered.div_checked(div_factor)
173 } else {
174 // mul_exp is negative, so we multiply by 10^(-mul_exp)
175 let abs_exp = mul_exp.checked_neg().ok_or_else(|| {
176 ArrowError::ArithmeticOverflow(
177 "Overflow while negating scale exponent".to_string(),
178 )
179 })?;
180 let mul_factor: T =
181 T::usize_as(10).pow_checked(abs_exp as u32).map_err(|_| {
182 ArrowError::ArithmeticOverflow(format!(
183 "Cannot make mul factor for {scale} and {exp}"

Callers 2

pow_decimal_floatFunction · 0.85
invoke_with_argsMethod · 0.85

Calls 3

pow_decimal_floatFunction · 0.85
mul_checkedMethod · 0.80
to_stringMethod · 0.45

Tested by

no test coverage detected

Used in the wild real call sites across dependent graphs

searching dependent graphs…