use crate::{ f16::F16, ieee754::FloatEncoding, traits::{Compare, Context, ConvertTo, Float, Select}, }; pub const DEFAULT_NAN_RESULT: i16 = i16::MIN + 1; pub const DEFAULT_OVERFLOW_RESULT: i16 = i16::MAX; pub const DEFAULT_UNDERFLOW_RESULT: i16 = i16::MIN; macro_rules! impl_ilogb { ( #[prim = $prim:ident] #[prim_signed_bits = $prim_signed_bits:ident] #[ilogb = $ilogb:ident] #[nan = $NAN_RESULT:ident] #[overflow = $OVERFLOW_RESULT:ident] #[underflow = $UNDERFLOW_RESULT:ident] fn $ilogb_extended:ident($vector_float:ident, $scalar_signed_bits:ident) -> $vector_signed_bits:ident; ) => { pub const $NAN_RESULT: $prim_signed_bits = $prim_signed_bits::MIN + 1; pub const $OVERFLOW_RESULT: $prim_signed_bits = $prim_signed_bits::MAX; pub const $UNDERFLOW_RESULT: $prim_signed_bits = $prim_signed_bits::MIN; pub fn $ilogb_extended( ctx: Ctx, arg: Ctx::$vector_float, nan_result: Ctx::$scalar_signed_bits, overflow_result: Ctx::$scalar_signed_bits, underflow_result: Ctx::$scalar_signed_bits, ) -> Ctx::$vector_signed_bits { let is_finite = arg.is_finite(); let is_zero_subnormal = arg.is_zero_or_subnormal(); let is_nan = arg.is_nan(); let inf_nan_result: Ctx::$vector_signed_bits = is_nan.select(nan_result.into(), overflow_result.into()); let scale_factor: $prim = (1u64 << $prim::MANTISSA_FIELD_WIDTH).to(); let scaled = arg * ctx.make(scale_factor); let scaled_exponent = scaled.extract_exponent_unbiased(); let exponent = arg.extract_exponent_unbiased(); let normal_inf_nan_result = is_finite.select(exponent, inf_nan_result); let is_zero = arg.eq(ctx.make($prim::from(0u8))); let zero_subnormal_result = is_zero.select( underflow_result.into(), scaled_exponent - ctx.make($prim::MANTISSA_FIELD_WIDTH.to()), ); is_zero_subnormal.select(zero_subnormal_result, normal_inf_nan_result) } pub fn $ilogb(ctx: Ctx, arg: Ctx::$vector_float) -> Ctx::$vector_signed_bits { $ilogb_extended( ctx, arg, ctx.make($NAN_RESULT), ctx.make($OVERFLOW_RESULT), ctx.make($UNDERFLOW_RESULT), ) } }; } impl_ilogb! { #[prim = F16] #[prim_signed_bits = i16] #[ilogb = ilogb_f16] #[nan = ILOGB_NAN_RESULT_F16] #[overflow = ILOGB_OVERFLOW_RESULT_F16] #[underflow = ILOGB_UNDERFLOW_RESULT_F16] fn ilogb_f16_extended(VecF16, I16) -> VecI16; } impl_ilogb! { #[prim = f32] #[prim_signed_bits = i32] #[ilogb = ilogb_f32] #[nan = ILOGB_NAN_RESULT_F32] #[overflow = ILOGB_OVERFLOW_RESULT_F32] #[underflow = ILOGB_UNDERFLOW_RESULT_F32] fn ilogb_f32_extended(VecF32, I32) -> VecI32; } impl_ilogb! { #[prim = f64] #[prim_signed_bits = i64] #[ilogb = ilogb_f64] #[nan = ILOGB_NAN_RESULT_F64] #[overflow = ILOGB_OVERFLOW_RESULT_F64] #[underflow = ILOGB_UNDERFLOW_RESULT_F64] fn ilogb_f64_extended(VecF64, I64) -> VecI64; } #[cfg(test)] mod tests { use super::*; use crate::scalar::Scalar; #[test] fn test_ilogb_f32() { assert_eq!(ilogb_f32(Scalar, 0f32), ILOGB_UNDERFLOW_RESULT_F32); assert_eq!(ilogb_f32(Scalar, 1f32), 0); assert_eq!(ilogb_f32(Scalar, 2f32), 1); assert_eq!(ilogb_f32(Scalar, 3f32), 1); assert_eq!(ilogb_f32(Scalar, 3.99999f32), 1); assert_eq!(ilogb_f32(Scalar, 0.5f32), -1); assert_eq!(ilogb_f32(Scalar, 0.5f32.powi(130)), -130); assert_eq!(ilogb_f32(Scalar, f32::INFINITY), ILOGB_OVERFLOW_RESULT_F32); assert_eq!(ilogb_f32(Scalar, f32::NAN), ILOGB_NAN_RESULT_F32); } #[test] fn test_ilogb_f64() { assert_eq!(ilogb_f64(Scalar, 0f64), ILOGB_UNDERFLOW_RESULT_F64); assert_eq!(ilogb_f64(Scalar, 1f64), 0); assert_eq!(ilogb_f64(Scalar, 2f64), 1); assert_eq!(ilogb_f64(Scalar, 3f64), 1); assert_eq!(ilogb_f64(Scalar, 3.99999f64), 1); assert_eq!(ilogb_f64(Scalar, 0.5f64), -1); assert_eq!(ilogb_f64(Scalar, 0.5f64.powi(1030)), -1030); assert_eq!(ilogb_f64(Scalar, f64::INFINITY), ILOGB_OVERFLOW_RESULT_F64); assert_eq!(ilogb_f64(Scalar, f64::NAN), ILOGB_NAN_RESULT_F64); } }