Skip to content
63 changes: 63 additions & 0 deletions datafusion/common/src/scalar/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@

// Constants defined for scalar construction.

use arrow::datatypes::{Decimal32Type, Decimal64Type, Decimal128Type, DecimalType};
use arrow::datatypes::{Decimal256Type, i256};

// Next F16 value above π (upper bound)
pub(super) const PI_UPPER_F16: half::f16 = half::f16::from_bits(0x4249);

Expand Down Expand Up @@ -54,3 +57,63 @@ pub(super) const NEGATIVE_FRAC_PI_2_LOWER_F32: f32 =
// Next f64 value below -π/2 (lower bound)
pub(super) const NEGATIVE_FRAC_PI_2_LOWER_F64: f64 =
(-std::f64::consts::FRAC_PI_2).next_down();

// Generate lookup table for 1 values of decimals (1, 10, 100, etc.)
macro_rules! decimal_ones_lut {
() => {{
let mut values = [1; _];
let mut i = 1;
while i < values.len() {
values[i] = values[i - 1] * 10;
i += 1;
}
values
}};
}

// 1, 10, 100 values meant to be indexed by scale. We omit handling for MAX_SCALE
// itself (we don't go to MAX_SCALE + 1) since we can't represent a 1 value at
// that scale.
pub(super) const DECIMAL32_ONES: [i32; Decimal32Type::MAX_SCALE as usize] =
decimal_ones_lut!();
pub(super) const DECIMAL64_ONES: [i64; Decimal64Type::MAX_SCALE as usize] =
decimal_ones_lut!();
pub(super) const DECIMAL128_ONES: [i128; Decimal128Type::MAX_SCALE as usize] =
decimal_ones_lut!();
pub(super) const DECIMAL256_ONES: [i256; Decimal256Type::MAX_SCALE as usize] = {
// This code was generated by codex and frankly I don't know how it works,
// but the test below verifies it outputs the correct values so ¯\_(ツ)_/¯
//
// This is mainly a shortcut for not needing to manually list out each value
// anyway.
//
// TODO: simplify this after https://github.com/apache/arrow-rs/pull/10363
// lands upstream
let mut values = [i256::ONE; _];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is basically const mul? I also ran into that recently elsewhere, so figured I'll make a PR - apache/arrow-rs#10363

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this would be very helpful indeed 🙏

let mut i = 1;
while i < values.len() {
let (low, high) = values[i - 1].to_parts();
let low_product = (low as u64 as u128) * 10;
let high_product = (low >> 64) * 10 + (low_product >> 64);
let low = ((high_product as u64 as u128) << 64) | low_product as u64 as u128;
let carry = (high_product >> 64) as i128;
values[i] = i256::from_parts(low, high * 10 + carry);
i += 1;
}
values
};

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_ensure_correct_decimal256_ones() {
for (scale, val) in DECIMAL256_ONES.iter().enumerate() {
let zeros = "0".repeat(scale);
let num = "1".to_string() + &zeros;
let num = i256::from_string(&num).unwrap();
assert_eq!(num, *val, "{scale}");
}
}
}
Loading
Loading