2956c8f5027f15b6a7454d28a3b25cfdd45539d8
[vector-math.git] / src / algorithms / ilogb.rs
1 use crate::{
2 f16::F16,
3 ieee754::FloatEncoding,
4 traits::{Compare, Context, ConvertTo, Float, Select},
5 };
6
7 pub const DEFAULT_NAN_RESULT: i16 = i16::MIN + 1;
8 pub const DEFAULT_OVERFLOW_RESULT: i16 = i16::MAX;
9 pub const DEFAULT_UNDERFLOW_RESULT: i16 = i16::MIN;
10
11 macro_rules! impl_ilogb {
12 (
13 #[prim = $prim:ident]
14 #[prim_signed_bits = $prim_signed_bits:ident]
15 #[ilogb = $ilogb:ident]
16 #[nan = $NAN_RESULT:ident]
17 #[overflow = $OVERFLOW_RESULT:ident]
18 #[underflow = $UNDERFLOW_RESULT:ident]
19 fn $ilogb_extended:ident($vector_float:ident, $scalar_signed_bits:ident) -> $vector_signed_bits:ident;
20 ) => {
21 pub const $NAN_RESULT: $prim_signed_bits = $prim_signed_bits::MIN + 1;
22 pub const $OVERFLOW_RESULT: $prim_signed_bits = $prim_signed_bits::MAX;
23 pub const $UNDERFLOW_RESULT: $prim_signed_bits = $prim_signed_bits::MIN;
24
25 pub fn $ilogb_extended<Ctx: Context>(
26 ctx: Ctx,
27 arg: Ctx::$vector_float,
28 nan_result: Ctx::$scalar_signed_bits,
29 overflow_result: Ctx::$scalar_signed_bits,
30 underflow_result: Ctx::$scalar_signed_bits,
31 ) -> Ctx::$vector_signed_bits {
32 let is_finite = arg.is_finite();
33 let is_zero_subnormal = arg.is_zero_or_subnormal();
34 let is_nan = arg.is_nan();
35 let inf_nan_result: Ctx::$vector_signed_bits =
36 is_nan.select(nan_result.into(), overflow_result.into());
37 let scale_factor: $prim = (1u64 << $prim::MANTISSA_FIELD_WIDTH).to();
38 let scaled = arg * ctx.make(scale_factor);
39 let scaled_exponent = scaled.extract_exponent_unbiased();
40 let exponent = arg.extract_exponent_unbiased();
41 let normal_inf_nan_result = is_finite.select(exponent, inf_nan_result);
42 let is_zero = arg.eq(ctx.make($prim::from(0u8)));
43 let zero_subnormal_result = is_zero.select(
44 underflow_result.into(),
45 scaled_exponent - ctx.make($prim::MANTISSA_FIELD_WIDTH.to()),
46 );
47 is_zero_subnormal.select(zero_subnormal_result, normal_inf_nan_result)
48 }
49
50 pub fn $ilogb<Ctx: Context>(ctx: Ctx, arg: Ctx::$vector_float) -> Ctx::$vector_signed_bits {
51 $ilogb_extended(
52 ctx,
53 arg,
54 ctx.make($NAN_RESULT),
55 ctx.make($OVERFLOW_RESULT),
56 ctx.make($UNDERFLOW_RESULT),
57 )
58 }
59 };
60 }
61
62 impl_ilogb! {
63 #[prim = F16]
64 #[prim_signed_bits = i16]
65 #[ilogb = ilogb_f16]
66 #[nan = ILOGB_NAN_RESULT_F16]
67 #[overflow = ILOGB_OVERFLOW_RESULT_F16]
68 #[underflow = ILOGB_UNDERFLOW_RESULT_F16]
69 fn ilogb_f16_extended(VecF16, I16) -> VecI16;
70 }
71
72 impl_ilogb! {
73 #[prim = f32]
74 #[prim_signed_bits = i32]
75 #[ilogb = ilogb_f32]
76 #[nan = ILOGB_NAN_RESULT_F32]
77 #[overflow = ILOGB_OVERFLOW_RESULT_F32]
78 #[underflow = ILOGB_UNDERFLOW_RESULT_F32]
79 fn ilogb_f32_extended(VecF32, I32) -> VecI32;
80 }
81
82 impl_ilogb! {
83 #[prim = f64]
84 #[prim_signed_bits = i64]
85 #[ilogb = ilogb_f64]
86 #[nan = ILOGB_NAN_RESULT_F64]
87 #[overflow = ILOGB_OVERFLOW_RESULT_F64]
88 #[underflow = ILOGB_UNDERFLOW_RESULT_F64]
89 fn ilogb_f64_extended(VecF64, I64) -> VecI64;
90 }
91
92 #[cfg(test)]
93 mod tests {
94 use super::*;
95 use crate::scalar::Scalar;
96
97 #[test]
98 fn test_ilogb_f32() {
99 assert_eq!(ilogb_f32(Scalar, 0f32), ILOGB_UNDERFLOW_RESULT_F32);
100 assert_eq!(ilogb_f32(Scalar, 1f32), 0);
101 assert_eq!(ilogb_f32(Scalar, 2f32), 1);
102 assert_eq!(ilogb_f32(Scalar, 3f32), 1);
103 assert_eq!(ilogb_f32(Scalar, 3.99999f32), 1);
104 assert_eq!(ilogb_f32(Scalar, 0.5f32), -1);
105 assert_eq!(ilogb_f32(Scalar, 0.5f32.powi(130)), -130);
106 assert_eq!(ilogb_f32(Scalar, f32::INFINITY), ILOGB_OVERFLOW_RESULT_F32);
107 assert_eq!(ilogb_f32(Scalar, f32::NAN), ILOGB_NAN_RESULT_F32);
108 }
109
110 #[test]
111 fn test_ilogb_f64() {
112 assert_eq!(ilogb_f64(Scalar, 0f64), ILOGB_UNDERFLOW_RESULT_F64);
113 assert_eq!(ilogb_f64(Scalar, 1f64), 0);
114 assert_eq!(ilogb_f64(Scalar, 2f64), 1);
115 assert_eq!(ilogb_f64(Scalar, 3f64), 1);
116 assert_eq!(ilogb_f64(Scalar, 3.99999f64), 1);
117 assert_eq!(ilogb_f64(Scalar, 0.5f64), -1);
118 assert_eq!(ilogb_f64(Scalar, 0.5f64.powi(1030)), -1030);
119 assert_eq!(ilogb_f64(Scalar, f64::INFINITY), ILOGB_OVERFLOW_RESULT_F64);
120 assert_eq!(ilogb_f64(Scalar, f64::NAN), ILOGB_NAN_RESULT_F64);
121 }
122 }