add sin_pi_f16, cos_pi_f16, and sin_cos_pi_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 macro_rules! impl_ilogb {
8 (
9 #[prim = $prim:ident]
10 #[prim_signed_bits = $prim_signed_bits:ident]
11 #[ilogb = $ilogb:ident]
12 #[nan = $NAN_RESULT:ident]
13 #[overflow = $OVERFLOW_RESULT:ident]
14 #[underflow = $UNDERFLOW_RESULT:ident]
15 fn $ilogb_extended:ident($vector_float:ident, $scalar_signed_bits:ident) -> $vector_signed_bits:ident;
16 ) => {
17 pub const $NAN_RESULT: $prim_signed_bits = $prim_signed_bits::MIN + 1;
18 pub const $OVERFLOW_RESULT: $prim_signed_bits = $prim_signed_bits::MAX;
19 pub const $UNDERFLOW_RESULT: $prim_signed_bits = $prim_signed_bits::MIN;
20
21 pub fn $ilogb_extended<Ctx: Context>(
22 ctx: Ctx,
23 arg: Ctx::$vector_float,
24 nan_result: Ctx::$scalar_signed_bits,
25 overflow_result: Ctx::$scalar_signed_bits,
26 underflow_result: Ctx::$scalar_signed_bits,
27 ) -> Ctx::$vector_signed_bits {
28 let is_finite = arg.is_finite();
29 let is_zero_subnormal = arg.is_zero_or_subnormal();
30 let is_nan = arg.is_nan();
31 let inf_nan_result: Ctx::$vector_signed_bits =
32 is_nan.select(nan_result.into(), overflow_result.into());
33 let scale_factor: $prim = (1u64 << $prim::MANTISSA_FIELD_WIDTH).to();
34 let scaled = arg * ctx.make(scale_factor);
35 let scaled_exponent = scaled.extract_exponent_unbiased();
36 let exponent = arg.extract_exponent_unbiased();
37 let normal_inf_nan_result = is_finite.select(exponent, inf_nan_result);
38 let is_zero = arg.eq(ctx.make($prim::from(0u8)));
39 let zero_subnormal_result = is_zero.select(
40 underflow_result.into(),
41 scaled_exponent - ctx.make($prim::MANTISSA_FIELD_WIDTH.to()),
42 );
43 is_zero_subnormal.select(zero_subnormal_result, normal_inf_nan_result)
44 }
45
46 pub fn $ilogb<Ctx: Context>(ctx: Ctx, arg: Ctx::$vector_float) -> Ctx::$vector_signed_bits {
47 $ilogb_extended(
48 ctx,
49 arg,
50 ctx.make($NAN_RESULT),
51 ctx.make($OVERFLOW_RESULT),
52 ctx.make($UNDERFLOW_RESULT),
53 )
54 }
55 };
56 }
57
58 impl_ilogb! {
59 #[prim = F16]
60 #[prim_signed_bits = i16]
61 #[ilogb = ilogb_f16]
62 #[nan = ILOGB_NAN_RESULT_F16]
63 #[overflow = ILOGB_OVERFLOW_RESULT_F16]
64 #[underflow = ILOGB_UNDERFLOW_RESULT_F16]
65 fn ilogb_f16_extended(VecF16, I16) -> VecI16;
66 }
67
68 impl_ilogb! {
69 #[prim = f32]
70 #[prim_signed_bits = i32]
71 #[ilogb = ilogb_f32]
72 #[nan = ILOGB_NAN_RESULT_F32]
73 #[overflow = ILOGB_OVERFLOW_RESULT_F32]
74 #[underflow = ILOGB_UNDERFLOW_RESULT_F32]
75 fn ilogb_f32_extended(VecF32, I32) -> VecI32;
76 }
77
78 impl_ilogb! {
79 #[prim = f64]
80 #[prim_signed_bits = i64]
81 #[ilogb = ilogb_f64]
82 #[nan = ILOGB_NAN_RESULT_F64]
83 #[overflow = ILOGB_OVERFLOW_RESULT_F64]
84 #[underflow = ILOGB_UNDERFLOW_RESULT_F64]
85 fn ilogb_f64_extended(VecF64, I64) -> VecI64;
86 }
87
88 #[cfg(test)]
89 mod tests {
90 use super::*;
91 use crate::scalar::{Scalar, Value};
92
93 #[test]
94 #[cfg_attr(
95 not(feature = "f16"),
96 should_panic(expected = "f16 feature is not enabled")
97 )]
98 fn test_ilogb_f16() {
99 fn ilogb(arg: f32) -> i16 {
100 let arg: F16 = arg.to();
101 ilogb_f16(Scalar, Value(arg)).0
102 }
103 assert_eq!(ilogb(0.), ILOGB_UNDERFLOW_RESULT_F16);
104 assert_eq!(ilogb(1.), 0);
105 assert_eq!(ilogb(2.), 1);
106 assert_eq!(ilogb(3.), 1);
107 assert_eq!(ilogb(3.998), 1);
108 assert_eq!(ilogb(0.5), -1);
109 assert_eq!(ilogb(0.5f32.powi(20)), -20);
110 assert_eq!(ilogb(f32::INFINITY), ILOGB_OVERFLOW_RESULT_F16);
111 assert_eq!(ilogb(f32::NAN), ILOGB_NAN_RESULT_F16);
112 }
113
114 #[test]
115 fn test_ilogb_f32() {
116 fn ilogb(arg: f32) -> i32 {
117 ilogb_f32(Scalar, Value(arg)).0
118 }
119 assert_eq!(ilogb(0f32), ILOGB_UNDERFLOW_RESULT_F32);
120 assert_eq!(ilogb(1f32), 0);
121 assert_eq!(ilogb(2f32), 1);
122 assert_eq!(ilogb(3f32), 1);
123 assert_eq!(ilogb(3.99999f32), 1);
124 assert_eq!(ilogb(0.5f32), -1);
125 assert_eq!(ilogb(0.5f32.powi(130)), -130);
126 assert_eq!(ilogb(f32::INFINITY), ILOGB_OVERFLOW_RESULT_F32);
127 assert_eq!(ilogb(f32::NAN), ILOGB_NAN_RESULT_F32);
128 }
129
130 #[test]
131 fn test_ilogb_f64() {
132 fn ilogb(arg: f64) -> i64 {
133 ilogb_f64(Scalar, Value(arg)).0
134 }
135 assert_eq!(ilogb(0f64), ILOGB_UNDERFLOW_RESULT_F64);
136 assert_eq!(ilogb(1f64), 0);
137 assert_eq!(ilogb(2f64), 1);
138 assert_eq!(ilogb(3f64), 1);
139 assert_eq!(ilogb(3.99999f64), 1);
140 assert_eq!(ilogb(0.5f64), -1);
141 assert_eq!(ilogb(0.5f64.powi(1030)), -1030);
142 assert_eq!(ilogb(f64::INFINITY), ILOGB_OVERFLOW_RESULT_F64);
143 assert_eq!(ilogb(f64::NAN), ILOGB_NAN_RESULT_F64);
144 }
145 }