add test_ilogb_f16
[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 #[cfg_attr(
99 not(feature = "f16"),
100 should_panic(expected = "f16 feature is not enabled")
101 )]
102 fn test_ilogb_f16() {
103 fn ilogb(arg: f32) -> i16 {
104 let arg: F16 = arg.to();
105 ilogb_f16(Scalar, arg)
106 }
107 assert_eq!(ilogb(0.), ILOGB_UNDERFLOW_RESULT_F16);
108 assert_eq!(ilogb(1.), 0);
109 assert_eq!(ilogb(2.), 1);
110 assert_eq!(ilogb(3.), 1);
111 assert_eq!(ilogb(3.998), 1);
112 assert_eq!(ilogb(0.5), -1);
113 assert_eq!(ilogb(0.5f32.powi(20)), -20);
114 assert_eq!(ilogb(f32::INFINITY), ILOGB_OVERFLOW_RESULT_F16);
115 assert_eq!(ilogb(f32::NAN), ILOGB_NAN_RESULT_F16);
116 }
117
118 #[test]
119 fn test_ilogb_f32() {
120 assert_eq!(ilogb_f32(Scalar, 0f32), ILOGB_UNDERFLOW_RESULT_F32);
121 assert_eq!(ilogb_f32(Scalar, 1f32), 0);
122 assert_eq!(ilogb_f32(Scalar, 2f32), 1);
123 assert_eq!(ilogb_f32(Scalar, 3f32), 1);
124 assert_eq!(ilogb_f32(Scalar, 3.99999f32), 1);
125 assert_eq!(ilogb_f32(Scalar, 0.5f32), -1);
126 assert_eq!(ilogb_f32(Scalar, 0.5f32.powi(130)), -130);
127 assert_eq!(ilogb_f32(Scalar, f32::INFINITY), ILOGB_OVERFLOW_RESULT_F32);
128 assert_eq!(ilogb_f32(Scalar, f32::NAN), ILOGB_NAN_RESULT_F32);
129 }
130
131 #[test]
132 fn test_ilogb_f64() {
133 assert_eq!(ilogb_f64(Scalar, 0f64), ILOGB_UNDERFLOW_RESULT_F64);
134 assert_eq!(ilogb_f64(Scalar, 1f64), 0);
135 assert_eq!(ilogb_f64(Scalar, 2f64), 1);
136 assert_eq!(ilogb_f64(Scalar, 3f64), 1);
137 assert_eq!(ilogb_f64(Scalar, 3.99999f64), 1);
138 assert_eq!(ilogb_f64(Scalar, 0.5f64), -1);
139 assert_eq!(ilogb_f64(Scalar, 0.5f64.powi(1030)), -1030);
140 assert_eq!(ilogb_f64(Scalar, f64::INFINITY), ILOGB_OVERFLOW_RESULT_F64);
141 assert_eq!(ilogb_f64(Scalar, f64::NAN), ILOGB_NAN_RESULT_F64);
142 }
143 }