fastalp 0.1.7

High-performance lossless floating-point compression in pure Rust / 基于 ALP 算法的高性能无损浮点数压缩库
Documentation
use crate::constants::AlpFloat;

/// 采样与最优系数选择结果
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct BestParams {
  pub exp: u8,
  pub fac: u8,
}

pub const SAMPLES_COUNT: usize = 32;

/// 检查 f64 是否为不可编码的特殊值(NaN, Inf, -0.0, 超出 i64 范围)
#[inline(always)]
pub fn is_impossible_f64(n: f64) -> bool {
  n.is_impossible()
}

/// 检查 f32 是否为不可编码的特殊值
#[inline(always)]
pub fn is_impossible_f32(n: f32) -> bool {
  n.is_impossible()
}

/// 高性能单值 f64 编码探测(已预提取幂表因子)
#[inline(always)]
pub fn try_encode_fast_f64(val: f64, exp_factor: f64, fac_int: i64, frac_exp: f64) -> Option<i64> {
  val.try_encode_fast(exp_factor, fac_int, frac_exp)
}

/// 尝试将单个 f64 编码为 i64,并验证反解是否 100% 精确无损
#[inline(always)]
pub fn try_encode_value_f64(val: f64, exp: u8, fac: u8) -> Option<i64> {
  if exp > f64::MAX_EXPONENT || fac > exp || fac > f64::MAX_FAC {
    return None;
  }
  let exp_factor = f64::exp_factor(exp, fac);
  let fac_int = f64::fac_int(fac);
  let frac_exp = f64::frac_exp(exp);
  val.try_encode_fast(exp_factor, fac_int, frac_exp)
}

/// 高性能单值 f32 编码探测(已预提取幂表因子)
#[inline(always)]
pub fn try_encode_fast_f32(val: f32, exp_factor: f32, fac_int: i64, frac_exp: f32) -> Option<i32> {
  val.try_encode_fast(exp_factor, fac_int, frac_exp)
}

/// 尝试将单个 f32 编码为 i32,并验证反解是否 100% 精确无损
#[inline(always)]
pub fn try_encode_value_f32(val: f32, exp: u8, fac: u8) -> Option<i32> {
  if exp > f32::MAX_EXPONENT || fac > exp || fac > f32::MAX_FAC {
    return None;
  }
  let exp_factor = f32::exp_factor(exp, fac);
  let fac_int = f32::fac_int(fac);
  let frac_exp = f32::frac_exp(exp);
  val.try_encode_fast(exp_factor, fac_int, frac_exp)
}

/// 通用采样推导最优 (exp, fac) 组合
pub fn find_best_params<F: AlpFloat>(data: &[F]) -> BestParams {
  if data.is_empty() {
    return BestParams { exp: 0, fac: 0 };
  }

  let mut samples = [F::ZERO; SAMPLES_COUNT];
  let sample_len = data.len().min(SAMPLES_COUNT);
  if data.len() <= SAMPLES_COUNT {
    samples[..sample_len].copy_from_slice(data);
  } else {
    let step = data.len() / SAMPLES_COUNT;
    for (i, slot) in samples.iter_mut().enumerate() {
      // SAFETY: SAMPLES_COUNT 为 32,当 data.len() > 32 时 step >= 1,且 i < 32,因此 i * step <= 31 * (data.len() / 32) < data.len(),索引严格在合法区间内。
      *slot = unsafe { *data.get_unchecked(i * step) };
    }
  }
  let active_samples = &samples[..sample_len];

  // 常数/同值序列极速探测:如果采样全等,直接寻找首个有效 exp 并返回
  let first = active_samples[0];
  if active_samples.iter().all(|&v| v == first) {
    for exp in 0..=F::MAX_EXPONENT {
      let frac_exp = F::frac_exp(exp);
      let exp_factor = F::exp_factor(exp, 0);
      let fac_int = F::fac_int(0);
      if F::try_encode_fast(first, exp_factor, fac_int, frac_exp).is_some() {
        return BestParams { exp, fac: 0 };
      }
    }
    return BestParams { exp: 0, fac: 0 };
  }

  let mut best_cost = usize::MAX;
  let mut best_params = BestParams { exp: 0, fac: 0 };

  for exp in 0..=F::MAX_EXPONENT {
    let max_fac = exp.min(F::MAX_FAC);
    let frac_exp = F::frac_exp(exp);

    for fac in 0..=max_fac {
      let exp_factor = F::exp_factor(exp, fac);
      let fac_int = F::fac_int(fac);

      let mut exceptions = 0usize;
      let mut min_val = F::MAX_INT;
      let mut max_val = F::MIN_INT;

      for &val in active_samples {
        if let Some(enc) = F::try_encode_fast(val, exp_factor, fac_int, frac_exp) {
          min_val = min_val.min(enc);
          max_val = max_val.max(enc);
        } else {
          exceptions += 1;
          if exceptions * F::EXCEPTION_PENALTY >= best_cost {
            break;
          }
        }
      }

      if exceptions == sample_len || exceptions * F::EXCEPTION_PENALTY >= best_cost {
        continue;
      }

      let max_offset = if min_val <= max_val {
        F::calc_range(min_val, max_val)
      } else {
        0
      };
      let bit_width = F::bits_needed(max_offset) as usize;
      let total_cost = bit_width * sample_len + exceptions * F::EXCEPTION_PENALTY;

      if total_cost < best_cost {
        best_cost = total_cost;
        best_params = BestParams { exp, fac };
        if total_cost == 0 {
          return best_params;
        }
        if exceptions == 0 && bit_width <= 2 {
          return best_params;
        }
      }
    }
  }

  best_params
}

/// 为 f64 数组采样推导最优 (exp, fac) 组合
#[inline]
pub fn find_best_params_f64(data: &[f64]) -> BestParams {
  find_best_params(data)
}

/// 为 f32 数组采样推导最优 (exp, fac) 组合
#[inline]
pub fn find_best_params_f32(data: &[f32]) -> BestParams {
  find_best_params(data)
}